获取后,%NOTFOUND可以返回null吗?

时间:2012-06-30 09:55:55

标签: oracle plsql cursor

This question提出了一个非常有趣的观点;在Oracle文档中似乎存在一个矛盾,即在获取后%NOTFOUND是否可能为空。是吗?

引用11g documentation

  

注意:在例6-16中,如果FETCH从不提取行,则c1%NOTFOUND   始终为NULL并且永远不会退出循环。防止无限   循环,改为使用此EXIT语句:EXIT WHEN c1%NOTFOUND OR   (c1%NOTFOUND为空);

文档似乎直接与自身相矛盾,因为它还说明了以下内容,这意味着在获取%NOTFOUND 之后 不能为空。

  

%NOTFOUND(%FOUND的逻辑反面)返回:
  显式游标打开后但在第一次获取之前为NULL   如果最近从显式游标中获取的行返回了一行,则为FALSE   否则为

10g documentation有一个类似的警告,这不一定是直接的矛盾,因为它警告说,为了展示这种行为,获取可能无法成功执行。

  

在第一次获取之前,%NOTFOUND的计算结果为NULL。如果FETCH永远不会   执行成功后,EXIT WHEN条件永远不会为TRUE而且   循环永远不会退出。为安全起见,您可能需要使用以下内容   改为EXIT语句:

     

当c1%NOTFOUND或c1%NOTFOUND为空时退出;

在fetch执行后,在什么情况下获取“失败”或者%NOTFOUND可能会返回null?

3 个答案:

答案 0 :(得分:7)

我可以找到提取失败的情况:

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 ...

答案 1 :(得分:0)

我认为绊倒你的部分是:

  

如果FETCH从未成功执行,则EXIT WHEN条件永远不会为TRUE,并且永远不会退出循环。

过去的某个地方肯定有一个代码示例,如下所示:

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

鉴于这段代码,声明仍然是真的。如果提取从未执行(失败),则%NOTFOUND将为null。 EXIT WHEN条件不会计算为TRUE(null计算结果为false)。然后,确实,循环将永远持续。

答案 2 :(得分:-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

根据此测试,执行fetch后%NOTFOUND不会为NULL。这与10g和11g文档在%NOTFOUND属性的初始描述中所述的内容相匹配。关于循环永远不会退出的注释必须来自该示例的旧版本。由于它只是一个注释,我说可以安全地信任初始描述并忽略该注释。