我有以下代码片段(简化以排除无关的细节):
<<cursor_loop>>
LOOP
fetch c1 into somerecord;
EXECUTE IMMEDIATE 'begin EXIT cursor_loop WHEN 1 = 1; end;';
END LOOP cursor_loop;
当我运行这个时,它失败了,出现了一个PLS-00201: identifier 'CURSOR_LOOP' must be declared
错误。
如果我把循环标签放在execute immediate之外,我得到PLS-00376: illegal EXIT/CONTINUE statement; it must appear inside a loop
。
显然后者是错误的,但不清楚为什么前者是错误的。
可以在execute-immediate内的语句中退出这个循环吗?
由于作用域的关系,您不能在动态SQL中直接引用cursor_loop
,正如其他人已经说过的那样。如果你坚持这种模式,那么你可以使用绑定变量标志将状态信息从动态代码传递回静态代码;比如:
DECLARE
break_loop pls_integer;
...
break_loop := 0;
<<cursor_loop>>
LOOP
fetch c1 into somerecord;
EXECUTE IMMEDIATE 'begin if 1 = 1 then :break_loop := 1; end if; end;'
USING OUT break_loop;
EXIT cursor_loop WHEN break_loop = 1;
END LOOP cursor_loop;
...
稍微完整一点,但显然还是很做作,例如:
DECLARE
break_loop pls_integer;
somevar number;
c1 sys_refcursor;
BEGIN
OPEN c1 FOR
select 1 from dual
union all select 2 from dual
union all select 3 from dual;
break_loop := 0;
dbms_output.put_line('before loop, break_loop is ' || break_loop);
<<cursor_loop>>
LOOP
fetch c1 into somevar;
exit when c1%notfound;
dbms_output.put_line('got ' || somevar);
EXECUTE IMMEDIATE 'begin if :somevar = 2 then :break_loop := 1; end if; end;'
USING somevar, OUT break_loop;
EXIT cursor_loop WHEN break_loop = 1;
END LOOP cursor_loop;
dbms_output.put_line('after loop, break_loop is ' || break_loop);
END;
/
PL/SQL procedure successfully completed.
before loop, break_loop is 0
got 1
got 2
after loop, break_loop is 1
在获取值'3'之前,因为动态检查而退出循环。
不行。
动态SQL语句在单独的作用域中运行——它不能引用调用块中定义的变量或操作它们的值(当然,除非您的动态语句具有绑定变量,允许您显式地创建两者之间的接口,并使用EXECUTE IMMEDIATE
的USING
和INTO
子句来传递和返回值)。类似地,它不能引用循环名称,因为在执行动态语句时,该名称不在作用域中。
在这种情况下,不清楚为什么首先要使用EXECUTE IMMEDIATE
而不是将EXIT
编码为循环的正常部分。
我不这么认为。EXECUTE IMMEDIATE用于运行SQL语句,而不是任意块。来自文档:
https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/executeimmediate_statement.htmEXECUTE IMMEDIATE语句构建并执行动态SQL
语句在单个操作中。它是一种手段,使当地人动态SQL处理大多数动态SQL语句。