为何以下PL/SQL代码块的游标会重复返回EMP表中仅存在一次的SOM值
重复输出SOM的根因分析
- 出现重复输出的核心原因是显式游标的遍历代码逻辑顺序错误,错误的执行顺序导致变量残留的旧值被额外打印。
具体逻辑拆解
Oracle 显式游标的%NOTFOUND属性存在明确的判定规则:
- 当
FETCH操作成功取到一行有效数据时,%NOTFOUND返回FALSE,对应的接收变量会被更新为当前行的实际值; - 当
FETCH操作没有取到有效数据(即游标结果集已经被全部遍历完成)时,%NOTFOUND返回TRUE,接收变量不会被覆盖更新,会保留上一次成功取数时的旧值。
对照你现有代码的执行顺序(执行FETCH → 执行打印 → 检查游标状态决定是否退出),最后两轮循环的执行过程完全对应重复输出的现象:
- 游标遍历到表里真实存储的那一条SOM记录时:
- 执行
FETCH成功取到值,v_ename被赋值为'SOM',此时C%NOTFOUND为FALSE - 代码先执行
DBMS_OUTPUT.PUT_LINE(v_ename),输出第一遍SOM - 检查退出条件:
C%NOTFOUND为FALSE,不满足退出要求,进入下一轮循环
- 执行
- 下一轮循环执行无效取数:
- 执行
FETCH时,已经没有剩余的结果行,取数失败。这个过程中v_ename没有被新值覆盖,仍然保留上一次存的'SOM'值,此时C%NOTFOUND被置为TRUE - 代码先执行
DBMS_OUTPUT.PUT_LINE(v_ename),把变量里残留的'SOM'值第二次输出 - 最后检查退出条件:
C%NOTFOUND为TRUE,满足要求,跳出循环
这个流程走完,就会在真实SOM记录的输出之后,额外多输出一次残留的SOM值,和你观测到的输出现象完全匹配。
- 执行
代码修正方案
只需要调整退出判断和打印的执行顺序,在取数完成后先检查游标状态,满足退出条件就直接跳出、不执行后续打印逻辑即可。修正后的循环部分代码为:
OPEN C; LOOP FETCH C INTO v_ename; -- 先判断取数是否成功,失败就直接退出,不执行打印 EXIT WHEN C%NOTFOUND; -- 确认成功取到值后再执行打印 DBMS_OUTPUT.PUT_LINE(v_ename); END LOOP; CLOSE C;
调整后,当最后一次无效FETCH触发%NOTFOUND=TRUE时,会直接跳出循环,根本不会走到打印残留变量值的步骤,也就不会出现重复输出的问题。
内容的提问来源于stack exchange,提问作者Somnath Bose
相关产品推荐
相关产品推荐

