NO_DATA_FOUND仅在SELECT INTO未查到行或子过程内含未处理的SELECT INTO时触发;UPDATE/DELETE等DML语句不抛该异常,仅使SQL%ROWCOUNT=0;函数中触发则静默返回NULL。

NO_DATA_FOUND只在SELECT INTO中触发,其他场景捕获它等于白写。
哪些语句真会抛出NO_DATA_FOUND
只有两个地方会实际触发这个异常:
-
SELECT ... INTO语句查不到任何行时(必须是单行隐式查询) - 被调用的子过程内部含
SELECT INTO且未自行处理该异常,导致向上冒泡
常见误判点:UPDATE、DELETE、INSERT ... SELECT、BULK COLLECT即使没匹配到数据,也绝不会抛NO_DATA_FOUND——它们只让SQL%ROWCOUNT为0,流程照常继续。把WHEN NO_DATA_FOUND THEN写在UPDATE后面,永远进不去。
为什么EXCEPTION块写了却没效果
PL/SQL中异常一旦抛出,当前BEGIN-END块立即终止。如果你把SELECT INTO和后续逻辑写在同一层块里,捕获后整个块就结束了,后续语句不执行。
要让异常后还能继续干活,必须用嵌套块隔离风险操作:
DECLARE
v_salary NUMBER;
BEGIN
-- 其他逻辑:比如UPDATE、日志记录等
UPDATE emp SET sal = sal * 1.1 WHERE deptno = 10;
<p>-- 单独包一层,只放可能出错的SELECT INTO
BEGIN
SELECT sal INTO v_salary FROM emp WHERE empno = 9999;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_salary := 0; -- 设默认值
END;</p><p>-- 这里能正常执行,不受上面异常影响
INSERT INTO audit_log VALUES ('salary_check', v_salary);
END;</p>
函数里NO_DATA_FOUND行为更特殊
在SQL上下文中调用函数(如SELECT fn_test('x') FROM dual),即使函数体内有SELECT ... INTO触发NO_DATA_FOUND,也不会报错,而是整行返回NULL。这跟存储过程或匿名块的行为完全不同。
原因在于SQL引擎把NO_DATA_FOUND当作“无数据”信号而非错误,直接终止函数执行并返回空值;而PL/SQL引擎则严格按异常机制处理,必须显式捕获,否则中断。
所以别指望在函数里靠DBMS_OUTPUT调试NO_DATA_FOUND——它根本不会输出,也不会报错,静默失败是常态。
捕获之后到底该做什么
空DBMS_OUTPUT.PUT_LINE只是调试幻觉,上线后毫无意义。必须根据业务语义决定“没数据”代表什么:
- 是正常缺省?→ 直接赋默认值:
v_pref := 'DEFAULT' - 需降级查备表?→ 在
WHEN NO_DATA_FOUND THEN里再发一次SELECT INTO查历史视图 - 属数据一致性破坏?→ 立即用
RAISE_APPLICATION_ERROR(-20001, '客户ID丢失: ' || v_cid)中止并暴露问题
最易被忽略的一点:NO_DATA_FOUND不是兜底异常,它不覆盖TOO_MANY_ROWS、权限错误、类型转换失败等其它问题。真要健壮,得配合WHEN OTHERS THEN或明确列出多个WHEN分支,不能只靠它撑全场。











