是否可以使用sql%rowcount进行SELECT?

时间:2012-11-15 10:02:11

标签: oracle stored-procedures plsql oracle10g oracle11g

以下代码可能会返回多行。 sql%rowcount会返回提取的行数吗?

select * from emp where empname = 'Justin' and dept='IT'
if sql%rowcount>0
    ...

这是我的样本过程;我以正确的方式使用sql%rowcount吗?

CREATE PROCEDURE Procn(in_Hid IN VARCHAR2,outInststatus OUT VARCHAR2,outSockid IN NUMBER,outport OUT VARCHAR2,outIP OUT VARCHAR2,outretvalue OUT NUMBER)
AS
BEGIN
select INST_STATUS into outInststatus from TINST_child where INST_ID = in_Hid and INST_STATUS = 'Y';
if outInststatus = 'Y' then 
     select PORT_NUMBER,STATIC_IP into outport,outIP from TINST where INST_ID = in_Hid and IP_PORT_STATUS = 'Y';
    if sql%rowcount >= 1 then
       select SOCK_ID into outSockid from TINST where PORT_NUMBER = outport AND STATIC_IP = outIP;  
       outretvalue := 0;
    else
       outretvalue := -12;
    end if;
  EXCEPTION
  WHEN NO_DATA_FOUND THEN
   outretvalue := -13;
end if;
END;

2 个答案:

答案 0 :(得分:7)

是的,您可以使用SQL%ROWCOUNT。它在PL / SQL中有效。

但是,在PL / SQL中,查询结果需要在某处,例如进入PL / SQL表。 PL / SQL永远不会将结果发送到输出(终端,窗口等)。因此SELECT * FROM无效。

您的代码可能如下所示:

DECLARE
  TYPE emp_t ...;
  emp_tab emp_t;

BEGIN
  SELECT *
  BULK COLLECT INTO emp_tab
  FROM emp
  WHERE empname = 'Justin' AND dept='IT';

  IF sql%rowcount > 0 THEN
    .. do something ...
  END IF;
END;
/

<强>更新

更新后的问题表明您正在寻找其他内容。

选项1:使用例外

如果有0行或多于1行,则这些情况将单独处理(作为错误):

BEGIN
  select PORT_NUMBER,STATIC_IP into outport, outIP
  from TINST
  where INST_ID = in_Hid AND IP_PORT_STATUS = 'Y';

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    outretvalue := -12;
    RETURN;

  WHEN TOO_MANY_ROWS THEN
    outretvalue := -13;
    RETURN;
END;

选项2:使用汇总

使用聚合,查询将始终返回一行。如果现在源行与WHERE子句匹配,则两个结果值都将为NULL。如果WHERE子句匹配多行,则将采用最大值。

请注意,此查询可能会返回端口号和最初不在同一行的IP地址。

select MAX(PORT_NUMBER), MAX(STATIC_IP) into outport, outIP
from TINST
where INST_ID = in_Hid AND IP_PORT_STATUS = 'Y';

IF outport IS NULL OR outIP IS NULL THEN
    outretvalue := -12;
    RETURN;
END IF;

选项3:使用ROWNUM

此查询最多返回一行。如果没有与WHERE子句匹配的行,则抛出异常并需要处理:

BEGIN
  select PORT_NUMBER, STATIC_IP into outport, outIP
  from TINST
  where INST_ID = in_Hid AND IP_PORT_STATUS = 'Y'
  AND ROWNUM = 1;

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    outretvalue := -12;
    RETURN;

END;

答案 1 :(得分:1)

根据您的评论

  

如果第二次'select'查询返回多行,我想取第一行并用它处理

......这应该有效,但也许并不像你期望的那样,因为你没有定义“第一个”的含义。

CREATE PROCEDURE Procn(in_Hid IN VARCHAR2, outInststatus OUT VARCHAR2,
    outSockid IN NUMBER, outport OUT VARCHAR2, outIP OUT VARCHAR2,
    outretvalue OUT NUMBER)
AS
BEGIN
    select INST_STATUS into outInststatus
    from TINST_child
    where INST_ID = in_Hid and INST_STATUS = 'Y';

    -- no need to check if outInstatus is Y, that's all it can be here

    -- restricting with `rownum` means you'll get at most one row, so you will
    -- not get too_many_rows. But it will be an arbitrary row - you have no
    -- criteria to determine which of the multiple rows you want. And you can
    -- still get no_data_found which will go to the same exception and set -12
    select PORT_NUMBER, STATIC_IP into outport, outIP
    from TINST
    where INST_ID = in_Hid and IP_PORT_STATUS = 'Y'
    and rownum < 2;

    -- no need to check sql%rowcount; it can only be 1 here

    -- not clear if this can return multiple rows too, and what should happen
    -- if it can; could use rownum restriction but with the same caveats
    select SOCK_ID into outSockid
    from TINST
    where PORT_NUMBER = outport AND STATIC_IP = outIP;   

    outretvalue := 0;
EXCEPTION
    WHEN NO_DATA_FOUND THEN
        outretvalue := -12;
END;

exception处理程序适用于整个block。如果任何select语句没有找到任何行,则no_data_found例外将由该块处理,并将outretvalue设置为-12

如果您希望每个outretvalue使用不同的select,那么您可以将它们包装在子块中,每个子块都有自己的异常处理部分:

CREATE PROCEDURE Procn(in_Hid IN VARCHAR2, outInststatus OUT VARCHAR2,
    outSockid IN NUMBER, outport OUT VARCHAR2, outIP OUT VARCHAR2,
    outretvalue OUT NUMBER)
AS
BEGIN
    BEGIN
        select INST_STATUS into outInststatus
        from TINST_child
        where INST_ID = in_Hid and INST_STATUS = 'Y';
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            outretvalue := -12;
    END;

    BEGIN
        select PORT_NUMBER, STATIC_IP into outport, outIP
        from TINST
        where INST_ID = in_Hid and IP_PORT_STATUS = 'Y'
        and rownum < 2;
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            outretvalue := -13;
    END;

    BEGIN
        select SOCK_ID into outSockid
        from TINST
        where PORT_NUMBER = outport AND STATIC_IP = outIP;   
    EXCEPTION
        WHEN NO_DATA_FOUND THEN
            outretvalue := -14;
    END;

    outretvalue := 0;
END;

如果调用者需要知道哪个select失败了,并且如果你真的没有想到它们中的任何一个失败那么你只需要这样做就可能更常见的是不捕获异常而让调用者查看原始no_data_found并决定要做什么。取决于异常条件对您和您的应用程序的意义。