oracle - TOO_MANY_ROWS 引发,但变量仍然获得一个值

标签 oracle plsql oracle11g

我刚刚发现,如果您有一个引发 TOO_MANY_ROWS 异常的 SELECT INTO,该变量仍会从查询检索到的第一条记录中分配值。这是预期的行为吗?

这是我的例子:

for co in my_cursor loop
        l_sco_db_id := null;

    begin
      select db_id
        into l_sco_db_id
        from objects_tab
       where object_name  = co.object_name;

    exception
      when no_data_found then
        dbms_output.put_line('No objects_tab record found for Object ' || co.object_name);
      when too_many_rows then
        dbms_output.put_line('Multiple objects_tab records found for Object ' || co.object_name);
        l_sco_db_id := null;
    end;
end loop;

这是在一个循环内,所以我在开始时将变量设置为 null 以确保它是空白的,但是我不得不在 WHEN TOO_MANY_ROWS 异常中再次明确地这样做,这是我没想到的。我的同事(至少,那些直接听到的)也没有期望这个变量有一个值。

最佳答案

这是预期的行为,因为当你了解幕后发生的事情时,它是有道理的。但当你第一次看到它时,这绝对是一种看起来很奇怪的行为。从技术上讲,该行为被记录为未定义,因此不应依赖它,并且将来可能会发生变化。

在封面下,一个 select into只是语法糖

  • 打开光标
  • 从游标中取出一行到目标变量
  • 扔一个 no_data_found如果未获取任何行,则异常
  • 尝试从游标中获取第二行,抛出 too_many_rows如果第二次获取成功,则异常。

  • 鉴于此,目标变量将在第一次获取时写入是有道理的。 select into statement 的 Oracle 文档然而,指出

    PL/SQL raises the predefined exception TOO_MANY_ROWS and the values of the variables in the INTO clause are undefined.



    因此,Oracle 可以自由地保持该值不变,或者让变量具有获取的第一行或第二行的值,或者实际上是其他任何值。而且您不应该编写依赖于任何特定行为的代码。

    例如,如果您查看 this blog post from Jeff Kemp ,该变量采用获取的第一行中的值。但是如果你对 Jeff 的代码做一个小的调整,这样你就可以获取一个局部变量
    CREATE or replace PROCEDURE proc2 (v OUT NUMBER) IS
      l_v integer;
    BEGIN
       SELECT 1 INTO l_v FROM all_objects;
    EXCEPTION
       WHEN TOO_MANY_ROWS THEN
          dbms_output.put_line
             ('TOO MANY ROWS: v='
              || l_v);
          v := l_v;
    END;
    /
    

    然后行为会发生变化并且该值似乎不会被覆盖。
    DECLARE
       v NUMBER;
    BEGIN
       proc2(v);
       dbms_output.put_line('AFTER: v=' || v);
    END;
    /
    

    关于oracle - TOO_MANY_ROWS 引发,但变量仍然获得一个值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40138984/

    相关文章:

    java - 通过 Payara 4 诊断与 Oracle 的 XA 连接

    sql - H2 中的分层查询

    python - 将多个表数据从 SQL Server 迁移到 Oracle

    oracle - 如何以编程方式将用户添加到 Oracle APEX 4.x 中的访问控制列表?

    oracle - 如何查找表中长列的长度

    oracle - 不能使用 DBMS_RANDOM 函数

    java - SQL 无效列错误。在 sql Developer 中工作,在 java 中给出错误

    mysql - 子查询在更新集子句中返回超过 1 个值

    java - 如何在 java 中映射 TYPE TABLE OF VARCHAR2(5)?

    java - 用于空间查询的 Oracle SQL 11g CPU/IO 性能测量