【问题标题】:Is it possible to use sql%rowcount for SELECT?是否可以使用 sql%rowcount 进行 SELECT?
【发布时间】:2012-11-03 21:52:56
【问题描述】:

下面的代码可能返回不止一行。 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;

【问题讨论】:

  • 如果标记为 PL/SQL,那么您需要选择某些内容,在这种情况下,如果行数为零,您将获得 no_data_found 异常,或者如果是 too many rows大于 1,因此您可以使用异常处理来处理此问题;或使用显式游标。我认为需要更多背景信息。
  • @alex 我更新了我的代码我发布了一个示例代码我是否以正确的方式使用 sql%count?
  • 否; select ... into(除非你有 bulk collect into 就像 Codo 建议的那样)总是会返回一行,或者引发异常。想象一下有两个匹配的行; static_ip 的两个值中的哪一个在 outIP 中?只要有一行,您的代码就可以工作,但如果没有,您的代码就会失败。多于一行是否有效,如果有怎么办?
  • 另外,outInstatus 在您检查时只能是 Y - 如果您的第一个 select 中没有匹配的行,则在您到达 @987654335 之前将引发 no_data_found @。尽管构造无论如何都不正确,但如果sql%rowcount 为零——这是不可能的,你会在那里得到no_data_found——那么你就没有设置outretvalue。我不完全确定你是否需要打三下;这可能表明第三个select 也可以返回多行。我认为您需要澄清在各种情况下应该发生的事情。
  • @alex 1.我的第一个“选择”查询在一个表上,另外两个“选择”查询在另一个表上。 2.现在我将上面的代码更新为当找不到数据时而不是 else 3.如果第二个“选择”查询返回多行,我想取第一行并处理它。

标签: oracle stored-procedures plsql oracle10g oracle11g


【解决方案1】:

是的,您可以使用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;

【讨论】:

  • 如果获取多于一行,sql%rowcount 将返回 >1,否则会显示行数过多
  • @user1 - bulk collect 子句表示emp_tab PL/SQL 表中存储了多行。你不会从中得到too_many_rowsno_data_found。当您进行批量收集时,sql%rowcount 将具有行数;虽然我通常会参考emp_tab.count 来查看其中包含多少 - 因为sql%count 指的是最后一个查询,它只会短暂有用,而emp_tab.count 将保持正确。
【解决方案2】:

根据您的评论

如果第二个“选择”查询返回不止一行,我想取第一行并处理它

...这应该可以工作,但可能并不像您期望的那样,因为您尚未定义“第一个”的含义。

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

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

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 并决定要做什么。不过,这取决于异常条件对您和您的应用程序意味着什么。

【讨论】:

  • 但我的要求与你解释的完全不同 1.im 检查 outInstatus 是否为 Y 因为我需要允许下一步仅当它的 'Y' 时,它也可能返回 'N' 2.I不能用 rownum 进行限制,因为我需要多行将出现在第二个 SELECT QUERY 中,我需要在这里随机选择结果集中的第一行,无需根据任何标准进行选择。
  • @user1 - 1) 由于where 子句,它只能是YINST_STATUS 不能同时是 YN。 2)我怕我不听; “需要多行”和“随机选择第一行”(这样做)是矛盾的吗?
  • 先生,我的问题是在我上面的代码中,如果第一个 SELECT 查询返回'Y',那么如果 stmnt 则没有 pblm 它会处理。如果它返回'NO DATA',它将进入异常。如果它返回' N' 根据我写的过程,接下来的条件会去哪里?
  • @user1 - 它不能返回Nwhere 子句具有 and INST_STATUS = 'Y',因此您将过滤掉任何 N
  • @user1 - exception 适用于整个block,因此如果任何选择没有行,您将获得-12
猜你喜欢
  • 1970-01-01
  • 2016-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
  • 2010-09-08
相关资源
最近更新 更多