And*_*Dan 5 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;
Run Code Online (Sandbox Code Playgroud)
这是在一个循环内,所以我在开始时将变量设置为 null 以确保它是空白的,但是我不得不在 WHEN TOO_MANY_ROWS 异常中再次明确地这样做,这是我没想到的。我的同事(至少,那些直接听到的)也没有期望这个变量有一个值。
这是预期的行为,因为当你了解幕后发生的事情时,它是有道理的。但当你第一次看到它时,这绝对是一种看起来很奇怪的行为。从技术上讲,该行为被记录为未定义,因此不应依赖它,并且将来可能会发生变化。
在幕后, aselect into只是语法糖
no_data_found如果没有获取行则抛出异常too_many_rows如果第二次获取成功则抛出异常。鉴于此,目标变量将在第一次获取时写入是有道理的。但是,该select into语句的 Oracle 文档指出
PL/SQL 引发预定义的异常 TOO_MANY_ROWS 并且 INTO 子句中的变量值未定义。
因此,Oracle 可以自由地保持该值不变,或者让变量具有获取的第一行或第二行的值,或者实际上是其他任何值。并且您不应该编写依赖于任何特定行为的代码。
例如,如果您查看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;
/
Run Code Online (Sandbox Code Playgroud)
然后行为会发生变化并且该值似乎不会被覆盖。
DECLARE
v NUMBER;
BEGIN
proc2(v);
dbms_output.put_line('AFTER: v=' || v);
END;
/
Run Code Online (Sandbox Code Playgroud)