You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 01:13:28