pl/sql中for循环不自动处理%notfound,但无需手动判断——它自动完成游标打开、遍历、关闭,且只支持隐式游标或未打开的显式游标变量。
pl/sql 中 for 循环 自动处理 %notfound 吗?
不自动,但根本不需要你手动写 %notfound 判断——for 循环 内部已封装了游标打开、取值、关闭全过程,遍历完自动退出,连 fetch 都不用显式调用。
常见错误是把显式游标和 FOR 循环 混用:先 OPEN 游标,再套 FOR 循环,结果报错 ORA-06511: PL/SQL: cursor already open;或者误以为 FOR 循环 会像 WHILE 一样持续执行到 %NOTFOUND 为 TRUE,导致逻辑错乱。
-
FOR 循环只支持隐式游标(即直接写SELECT)或已声明的游标变量(非已打开的游标) - 若游标已
OPEN,必须改用LOOP ... FETCH ... EXIT WHEN %NOTFOUND结构 - 循环体中不能对同一游标再次
FETCH,否则可能跳过记录或重复取值
用 FOR 循环 替代 FETCH + %NOTFOUND 的标准写法
核心就一条:把 SELECT 直接塞进 FOR 循环 的 IN 子句里,PL/SQL 会自动声明、打开、遍历、关闭游标。
典型场景是处理查询结果集并做单条记录级操作,比如更新日志表、校验数据一致性、生成报表中间行。
- 隐式写法(最常用):
FOR r IN (SELECT empno, ename FROM emp WHERE deptno = 10) LOOP DBMS_OUTPUT.PUT_LINE(r.ename); END LOOP;
- 显式游标变量写法(需提前声明):
DECLARE CURSOR c IS SELECT empno FROM emp; BEGIN FOR r IN c LOOP -- 注意:这里 c 是游标名,不是已打开的游标变量 UPDATE emp SET sal = sal * 1.1 WHERE empno = r.empno; END LOOP; END; - 不支持
OPEN c; FOR r IN c LOOP这种组合,会编译失败
FOR 循环 和手动 FETCH 在性能与资源上的差异
看起来只是少写几行代码,实际影响在游标生命周期和异常处理上。
手动 FETCH 要求你严格配对 OPEN/CLOSE,漏掉 CLOSE 会导致游标句柄泄露;而 FOR 循环 在循环结束时自动 CLOSE,哪怕中途 EXIT 或抛异常,也会确保释放。
-
FOR 循环的隐式游标默认使用SELECT ... BULK COLLECT INTO优化机制(内部批量获取),比逐行FETCH略快,尤其在结果集较大时 - 无法在循环中修改正在遍历的游标定义(比如动态拼接
WHERE条件),因为游标结构在编译期就固定了 - 若需在循环中根据某条记录结果决定是否继续取下一条(如遇到错误就中断整个遍历),
FOR 循环不够灵活,得切回手动FETCH
容易被忽略的兼容性细节:Oracle 版本与游标变量
FOR 循环 支持游标变量(REF CURSOR)是从 Oracle 9i 开始的,但仅限强类型游标变量,且必须是已声明、未打开的状态。
常见坑是把动态打开的 REF CURSOR 直接丢进 FOR 循环,比如从存储过程返回一个已 OPEN 的游标,然后试图 FOR r IN v_cursor LOOP —— 这会报 ORA-06511: cursor already open。
- 正确做法是用
FETCH ... BULK COLLECT配合EXIT WHEN v_cursor%NOTFOUND - 若坚持用
FOR 循环,需将游标变量包装成函数返回隐式结果集(Oracle 12c+ 支持PIPELINED函数) - Oracle 12c 引入的
FOR UPDATE OF不能和FOR 循环共存,需回归传统OPEN/FETCH/UPDATE/CLOSE流程
事情说清了就结束










