9

以下のコードは、複数の行を返す場合があります。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;
4

2 に答える 2

8

はい、ご利用いただけます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: 集計を使用する

集計を使用すると、クエリは常に正確に 1 つの行を返します。ソース行が 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 を使用する

このクエリは最大で 1 行を返します。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;
于 2012-11-15T10:16:20.420 に答える
1

あなたのコメントに基づいて

2番目の「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全体に適用されます。いずれかのステートメントで行が見つからない場合、例外はそのブロックによって処理され、 に設定されます。selectno_data_foundoutretvalue-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を見て何をすべきかを決定させる方が一般的です。 . ただし、例外条件があなたとあなたのアプリケーションにとって何を意味するかによって異なります。

于 2012-11-15T11:39:03.393 に答える