我刚刚发现,如果您有一个引发 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/