我有以下代码段(已简化以排除无关的详细信息):
<<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
错误。
如果我将循环标签从执行立即数中删除,我会得到PLS-00376: illegal EXIT/CONTINUE statement; it must appear inside a loop
。
显然后者是错的,但目前尚不清楚为什么前者是。
这个循环可以从execute-immediate中的语句中退出吗?
答案 0 :(得分:4)
由于范围的原因,您无法直接在动态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”之前,由于动态检查而退出循环。
答案 1 :(得分:3)
不,你不能。
动态SQL语句在一个单独的作用域中运行 - 它不能引用调用块中定义的变量或操纵它们的值(当然,除非你的动态语句有绑定变量,允许你在它们之间显式创建一个接口其中两个USING
和INTO
子句EXECUTE IMMEDIATE
传入并返回值)。类似地,它不能引用循环名称,因为在执行动态语句时该名称不在范围内。
在这种情况下,您不清楚为什么要首先使用EXECUTE IMMEDIATE
而不是将EXIT
编码为循环的正常部分。< / p>
答案 2 :(得分:2)
我想不是。 EXECUTE IMMEDIATE用于运行SQL语句,而不是任何块。来自文档:
EXECUTE IMMEDIATE语句构建并执行动态SQL
单一操作中的陈述。这是本土的手段 动态SQL处理大多数动态SQL语句。