oracle 21c for循环本质是统一迭代器抽象:reverse、by、values of、indices of等均为可赋值/组合的iterator结构,支持多迭代器笛卡尔积、when/while谓词过滤及mutable/immutable变量控制,但需规避空集合未初始化、副作用表达式重求值等陷阱。
oracle 21c 的 for 循环不是“加了几个关键字”,而是把迭代逻辑抽象成可赋值、可组合、可复用的 iterator 结构。直接用老写法(比如嵌套 for i in 1..n loop)反而会错过性能和可读性提升。
多迭代器并行声明替代嵌套循环
以前要遍历两个维度,得写两层 FOR;21c 支持单层声明多个迭代器,语义更紧凑,且底层是笛卡尔积展开,避免了手写嵌套带来的栈开销和可读混乱。
-
FOR i IN 1..3, j IN REVERSE 10..12 LOOP等价于传统两层嵌套,但变量作用域清晰,不隐式嵌套作用域 - 任一迭代器为空(如
INDICES OF empty_collection),整个循环体跳过,不报错也不执行——这点比手动判空再进循环更安全 - 默认所有迭代变量是
MUTABLE,你在循环体内改i := 5不影响下一轮步进;显式加IMMUTABLE后,任何赋值都会触发编译错误PLS-00363
VALUES OF 和 INDICES OF 直接驱动集合遍历
不再需要先查 COUNT 再 FOR i IN 1..coll.COUNT,也不用担心空集合导致 NO_DATA_FOUND 或越界——只要集合已初始化(哪怕 COUNT = 0),语法就合法且静默跳过。
-
VALUES OF coll拿的是元素值,INDICES OF coll拿的是下标,二者不能混用在同一个迭代器位置 - 若
coll是VARCHAR2关联数组,INDICES OF coll返回的是PLS_INTEGER类型下标,不是字符串键 - 注意:必须确保集合已初始化,
DECLARE coll t_tab;(未赋值)后直接用INDICES OF coll会报ORA-06531: Reference to uninitialized collection
WHILE 和 WHEN 是迭代器谓词,不是控制语句
它们在每次生成下一个值前就做判断,不满足即终止迭代——被过滤掉的值根本不会进入循环体,也不会触发 EXIT 或异常。这和传统 IF ... EXIT WHEN 有本质区别。
FOR i IN 1..10 WHILE i 只执行 <code>i = 1,2,3,4,i = 5根本不会生成,更不会进循环体-
WHEN是跳过单次(类似 continue),WHILE是终止整个迭代;两者可共存,顺序无关 - 错误写法:
FOR i IN 1..10 LOOP IF i = 5 THEN EXIT; END IF;—— 这仍会生成i = 5,再在循环体内判断退出,多一次无意义绑定
BY 步长支持负值,但上下限与步长符号必须一致
10..1 BY -2 合法,输出 10,8,6,4,2;但 1..10 BY -1 会在运行时报 ORA-06502: PL/SQL: numeric or value error,因为步长方向与范围矛盾。
- 步长可以是变量或表达式,但必须在迭代开始前能求值为非零数
-
BY 0编译期就报错,不等到运行 - 使用
REVERSE时,步长符号自动适配:例如REVERSE 1..10 BY 2实际等价于10..1 BY -2
真正容易被忽略的是:所有这些新迭代器结构都依赖 PL/SQL 引擎对 iterator 的统一解析,一旦混用旧式循环逻辑(比如在 VALUES OF 循环里又去手动维护下标计数器),不仅失去语法优势,还可能因副作用重求值引发意外行为——比如 WHEN 谓词里调用带状态的函数,会被多次执行。











