首页 文章

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

提问于
浏览
9

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

引用11g documentation

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

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

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

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

在第一次获取之前,%NOTFOUND计算为NULL . 如果FETCH永远不会成功执行,则EXIT WHEN条件永远不会为TRUE,并且永远不会退出循环 . 为安全起见,您可能需要使用以下EXIT语句:EXIT WHEN c1%NOTFOUND或c1%NOTFOUND为NULL;

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

3 回答

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

  • 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) . 然后,确实,循环将永远持续下去 .

  • -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 . 这与10g和11g文档在 %NOTFOUND 属性的初始描述中所述的相匹配 . 关于循环永远不会退出的注释必须来自该示例的旧版本 . 因为's just a note, I'd说它可以安全地信任最初的描述并忽略该注释 .

相关问题