PL/SQL自定义异常失效:无法触发自定义报错提示
问题分析与解决:自定义异常未触发,抛出ORA-01403错误
你编写的PL/SQL代码定义了自定义异常e_no_employee,期望查询不到员工ID 9999时触发该异常并打印自定义提示,但实际运行抛出了ORA-01403系统错误,而非自定义提示。
问题原因
当SELECT INTO语句未返回任何行时,Oracle会直接抛出系统异常ORA-01403(NO_DATA_FOUND),代码无法执行到后续的IF v_employee_name IS NULL判断逻辑。因为SELECT INTO要求必须返回且仅返回一行数据,无匹配行时会立即触发系统异常,中断当前执行流程,所以你的自定义异常触发逻辑永远不会被执行。
解决方案
以下是几种可行的修正方案:
方案1:捕获系统NO_DATA_FOUND异常,转换为自定义异常处理
直接捕获系统抛出的无数据异常,再转换为自定义异常处理:
DECLARE v_employee_name employees.first_name%TYPE; v_employee_id employees.employee_id%TYPE := 9999; -- 定义自定义异常 e_no_employee EXCEPTION; BEGIN SELECT first_name INTO v_employee_name FROM employees WHERE employee_id = v_employee_id; DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_employee_name); EXCEPTION WHEN NO_DATA_FOUND THEN -- 捕获系统无数据异常 RAISE e_no_employee; -- 转换为自定义异常 WHEN e_no_employee THEN DBMS_OUTPUT.PUT_LINE('Error: No data found for Employee ID ' || v_employee_id); END; /
如果不需要中间转换,也可以直接在NO_DATA_FOUND分支处理提示:
DECLARE v_employee_name employees.first_name%TYPE; v_employee_id employees.employee_id%TYPE := 9999; BEGIN SELECT first_name INTO v_employee_name FROM employees WHERE employee_id = v_employee_id; DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_employee_name); EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('Error: No data found for Employee ID ' || v_employee_id); END; /
方案2:用EXCEPTION_INIT绑定自定义异常与系统错误码
通过PRAGMA EXCEPTION_INIT将自定义异常与ORA-01403的错误码绑定,这样可以直接捕获自定义异常:
DECLARE v_employee_name employees.first_name%TYPE; v_employee_id employees.employee_id%TYPE := 9999; -- 定义自定义异常并关联系统错误码 e_no_employee EXCEPTION; PRAGMA EXCEPTION_INIT(e_no_employee, -01403); -- 绑定ORA-01403错误码 BEGIN SELECT first_name INTO v_employee_name FROM employees WHERE employee_id = v_employee_id; DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_employee_name); EXCEPTION WHEN e_no_employee THEN DBMS_OUTPUT.PUT_LINE('Error: No data found for Employee ID ' || v_employee_id); END; /
方案3:先判断数据是否存在,再执行查询
通过COUNT(*)先检查是否有匹配数据,避免触发系统异常:
DECLARE v_employee_name employees.first_name%TYPE; v_employee_id employees.employee_id%TYPE := 9999; v_count NUMBER; -- 定义自定义异常 e_no_employee EXCEPTION; BEGIN SELECT COUNT(*) INTO v_count FROM employees WHERE employee_id = v_employee_id; IF v_count = 0 THEN RAISE e_no_employee; ELSE SELECT first_name INTO v_employee_name FROM employees WHERE employee_id = v_employee_id; DBMS_OUTPUT.PUT_LINE('Employee Name: ' || v_employee_name); END IF; EXCEPTION WHEN e_no_employee THEN DBMS_OUTPUT.PUT_LINE('Error: No data found for Employee ID ' || v_employee_id); END; /
方案对比
- 方案1和方案2符合PL/SQL原生异常处理机制,执行效率更高,推荐优先使用。
- 方案3避免了异常触发,但需要执行两次查询,性能略低,适合对异常处理有特殊需求的场景。
内容的提问来源于stack exchange,提问作者Rusimbi Patrick
相关产品推荐
相关产品推荐

