显式游标fetch后必须立即检查%notfound,否则会重复处理最后一行或引发ora-01403;错误写法如exit置于fetch前会导致游标未执行即退出,而漏检%notfound则使循环多执行一次。

游标打开后 fetch 未检查 %notfound 就继续取值
显式游标不会自动报错,fetch 执行完后,必须立刻检查 c%notfound 或 c%found。常见错误是写成:
- 先
fetch,再loop,但exit when c%notfound放在fetch前面——导致第一次fetch永远不执行,游标始终停在开头,%notfound为 true,直接退出 - 多次
fetch之间没做校验,第二次fetch时游标已耗尽,ORA-01403报出 - 把
select into当游标用:它本质是隐式单行查询,结果为空就直接抛NO_DATA_FOUND,不是靠%notfound
连接字段全为 NULL 或类型不匹配导致 full join 返回空
FULL JOIN 理论上只要任一表有数据,结果就不该为空。如果返回空,大概率不是语法问题,而是数据逻辑断层:
- 左右表的关联字段(如
id)全部为NULL:Oracle 中NULL = NULL为 false,无法匹配,且FULL JOIN不会保留两边都为NULL的行 - 字段类型不一致:比如左表是
NUMBER,右表是VARCHAR2存数字字符串,隐式转换失败或结果意外 -
WHERE条件写在FULL JOIN外层:过滤掉了所有已拼出来的行;应改用ON条件或把WHERE拆到子查询里 - 分区表查了不存在的
batch_date分区:实际没数据,SELECT COUNT(*)返回 0,FULL JOIN自然无源可连
游标条件本身没命中任何数据
游标定义里的 WHERE 条件太严、字段名写错、大小写敏感、或权限不足,都会让游标“打开即空”:
- 字段名拼错:
M3_AMT写成m3_amt或M3AMT,而表实际是区分大小写的(建表用了双引号) - 传参为空:
WHERE batch_date = :p_date,但:p_date是 null,Oracle 中col = null永远不成立 - 用户没被授予
SELECT权限:查询不报错,但返回空结果集——这是 Oracle 的静默行为,不是 bug - 数据未提交:另一会话插入但没
COMMIT,当前会话不可见
用 count(*) 预判游标是否为空反而引入性能陷阱
有人为避免空游标,先跑一条 SELECT COUNT(*),再决定是否打开游标。这看似稳妥,实则埋雷:
- 两次全表扫描:一次计数、一次取数,I/O 和执行计划开销翻倍
- 并发风险:两次查询之间数据可能被删/改,计数和实际游标结果不一致
- 小数据量时没必要:游标打开+首次
fetch+%notfound判断,成本远低于额外 count - 真正需要预判的场景,优先考虑
BULK COLLECT INTO后检查collection.COUNT,而非分两步
最常被忽略的是:游标为空不是错误,是常态。关键不在“怎么让它不空”,而在“怎么安全地处理它为空”。











