Oracle PL SQL:使用标签摆脱 for 循环

use*_*554 3 sql oracle label plsql for-loop

SET SERVEROUTPUT ON
BEGIN
  <<outer_loop>>
  FOR i IN 1..10 LOOP
    FOR i IN 1..3 LOOP
      EXIT outer_loop WHEN outer_loop.i = 3;
    DBMS_OUTPUT.PUT_LINE('outer i is:' || outer_loop.i || ' inner i is: ' ||i);
      GOTO goodbye;
    END LOOP;       
  END LOOP;
  <<goodbye>>
  NULL;
END;
/
Run Code Online (Sandbox Code Playgroud)

我有上面的代码,它给出了下面的结果,但我的笔记说永远不要这样做。为什么会这样呢?毕竟它确实有效。

anonymous block completed
outer i is:1 inner i is: 1
Run Code Online (Sandbox Code Playgroud)

Tha*_*man 6

几乎在每种语言中都不鼓励使用GOTO,主要是因为它会损害代码的可读性,是的,在您的情况下,更糟糕的是 \xe2\x80\x94 您正在跳过两层堆栈。

\n\n

除此之外,PL/SQL 还具有此功能,如果您不使用GOTO. 它很少有用,但代码中的符号正是用于此目的。

\n\n

假设您有两个这样嵌套的循环。

\n\n
BEGIN\n  <<outer>>\n  FOR i IN 1..2 LOOP\n    <<inner>>\n    FOR j IN 1..2 LOOP\n      dbms_output.put_line(\'In inner loop\');\n    END LOOP;\n\n    dbms_output.put_line(\'In outer loop\');\n  END LOOP;\n\n  dbms_output.put_line(\'Finished\');\nEND;\n
Run Code Online (Sandbox Code Playgroud)\n\n

显然,输出将是

\n\n
In inner loop\nIn inner loop\nIn outer loop\nIn inner loop\nIn inner loop\nIn outer loop\nFinished\n
Run Code Online (Sandbox Code Playgroud)\n\n

有时您需要在“正常”完成之前退出循环,因此您添加EXIT;.

\n\n
BEGIN\n  <<outer>>\n  FOR i IN 1..2 LOOP\n    <<inner>>\n    FOR j IN 1..2 LOOP\n      dbms_output.put_line(\'In inner loop\');\n      EXIT;\n    END LOOP;\n\n    dbms_output.put_line(\'In outer loop\');\n  END LOOP;\n\n  dbms_output.put_line(\'Finished\');\nEND;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这会导致外循环的每次迭代只执行一次嵌套循环。

\n\n
In inner loop\nIn outer loop\nIn inner loop\nIn outer loop\nFinished\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是您可能想完全中止处理,为此您可以在嵌套循环中设置一些标志变量并在外循环中检查其值,或者您可以指定要退出的循环。

\n\n
BEGIN\n  <<outer>>\n  FOR i IN 1..2 LOOP\n    <<inner>>\n    FOR j IN 1..2 LOOP\n      dbms_output.put_line(\'In inner loop\');\n      EXIT outer;\n    END LOOP;\n\n    dbms_output.put_line(\'In outer loop\');\n  END LOOP;\n\n  dbms_output.put_line(\'Finished\');\nEND;\n
Run Code Online (Sandbox Code Playgroud)\n\n

这样你就退出了两个循环。

\n\n
In inner loop\nFinished\n
Run Code Online (Sandbox Code Playgroud)\n\n

回到您的示例,如果消除 GOTO,您将在内部循环的第三次迭代中退出两个循环。

\n\n

我不会说这对可读性很有好处,而且我宁愿以某种方式通知外循环一些特殊的东西,而不是让内循环负责从外循环退出。

\n