10

この質問は非常に興味深い点を提起しました。%NOTFOUNDフェッチ後に null になる可能性があるかどうかについて、Oracle のドキュメントに矛盾があるようです。それは...ですか?

11gのドキュメントから引用するには

注意: 例6-16では、FETCHが行をフェッチしない場合、c1%NOTFOUNDは常にNULLになり、ループは終了しません。無限ループを回避するには、代わりに次の EXIT ステートメントを使用します。 EXIT WHEN c1%NOTFOUND OR (c1%NOTFOUND IS NULL);

ドキュメントは、次のようにも述べているため、直接矛盾しているようです。これは、フェッチ後はnullに%NOTFOUND ならないことを意味します。

%NOTFOUND (%FOUND の論理的な反対) の戻り値:
明示カーソルが開かれた後、最初のフェッチの前に NULL 明示カーソル
からの最新のフェッチが行を返した場合は FALSE、
それ以外の場合は TRUE

10gのドキュメントにも同様の警告がありますが、この動作が発生するためにフェッチが正常に実行されない可能性があることを警告しているため、必ずしも直接矛盾するわけではありません。

最初のフェッチの前に、%NOTFOUND は NULL と評価されます。FETCH が正常に実行されない場合、EXIT WHEN 条件が TRUE になることはなく、ループは終了しません。安全のために、代わりに次の EXIT ステートメントを使用することをお勧めします。

c1%NOTFOUND または c1%NOTFOUND が NULL の場合は終了します。

フェッチが「失敗」したり%NOTFOUND、フェッチの実行後に null が返されたりするのはどのような状況ですか?

4

3 に答える 3

8

フェッチが失敗する可能性がある状況を見つけることができます:

declare
  i integer;
  cursor c is
    select 1 / 0 from dual;
begin
  open c;

  begin
    fetch c
      into i;
  exception
    when others then
      dbms_output.put_line('ex');
  end;

  if c%notfound is null then
    dbms_output.put_line('null');
  elsif c%notfound then
    dbms_output.put_line('true');
  else
    dbms_output.put_line('false');
  end if;
  close c;

end;

ただし、10gでも11gでもnullと評価されるため、これは質問をより強力にするだけです...

于 2012-07-01T12:11:24.713 に答える
0

あなたをつまずかせている部分はこれだと思います:

FETCH が正常に実行されない場合、EXIT WHEN 条件が TRUE になることはなく、ループは終了しません。

過去のどこかに、次のようなコード例があったに違いありません。

LOOP
  FETCH c1 INTO name;
  EXIT WHEN c1%NOTFOUND;
  -- Do stuff
END LOOP;

このコードのチャンクが与えられると、ステートメントは真になります。フェッチが実行されない (失敗する) 場合、%NOTFOUND は null になります。条件はEXIT WHENTRUE と評価されません (null は false と評価されます)。そして、実際、ループは永遠に続きます。

于 2012-07-01T03:57:22.357 に答える
-1

これは、簡単にテストできる状況です。

SET SERVEROUT ON;

DECLARE
  -- this cursor returns a single row
  CURSOR c1 IS
    SELECT 1 FROM dual WHERE rownum = 1;

  -- this cursor returns no rows
  CURSOR c2 IS
    SELECT 1 FROM dual WHERE 1=0;

  v1 number;
BEGIN
  OPEN c1;
  FETCH c1 INTO v1; -- this returns a record
  FETCH c1 INTO v1; -- this does not return a record
  IF c1%NOTFOUND THEN
    dbms_output.put_line('c1%NOTFOUND: TRUE');
  ELSIF c1%NOTFOUND IS NULL THEN
    dbms_output.put_line('c1%NOTFOUND: NULL');
  ELSE
    dbms_output.put_line('c1%NOTFOUND: FALSE');
  END IF;
  CLOSE c1;

  OPEN c2;
  FETCH c2 INTO v1; -- this does not return a record
  IF c2%NOTFOUND THEN
    dbms_output.put_line('c2%NOTFOUND: TRUE');
  ELSIF c2%NOTFOUND IS NULL THEN
    dbms_output.put_line('c2%NOTFOUND: NULL');
  ELSE
    dbms_output.put_line('c2%NOTFOUND: FALSE');
  END IF;
  CLOSE c2;
END;
/

Oracle APEX 4.1 でのスクリプトの出力は次のとおりです (APEX は Oracle 11gR2 を実行していると思いますが、どのバージョンでもスクリプトを簡単に実行できます)。

c1%NOTFOUND: TRUE
c2%NOTFOUND: TRUE

このテストに基づいて%NOTFOUND、フェッチが実行された後は NULL になりません。%NOTFOUNDこれは、属性の最初の説明で 10g および 11g のドキュメントに記載されている内容と一致します。決して終了しないループに関するメモは、例の古いバージョンからのものでなければなりません。これは単なるメモなので、最初の説明を信頼してメモを無視しても安全だと思います。

于 2012-07-01T06:13:52.297 に答える