• Oracle(00):PL/SQL异常处理


    一、异常处理

    PL/SQL提供了良好的异常处理机制,当程序运行出现错误时就会触发异常。异常被触发时,程序执行即终止,在PL/SQL块中提供了异常处理的部分,从而可以捕获一个异常进行特殊处理。

    三种的异常类型:

    1. 预定义 ( Predefined )错误:
      --ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。
    2. 非预定义 ( Predefined )错误:
      --即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。
    3. 用户定义(User_define) 错误:
      --程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。

    异常的SQLCode 和 SQLERRM 

    EXCEPTION
    WHEN first_exception THEN <code to handle first exception >
    WHEN second_exception THEN <code to handle second exception >
    WHEN OTHERS THEN <code to handle others exception >
    END;

    由于ORACLE 的错信息最大长度是512字节,为了得到完整的错误提示信息,我们可用 SQLERRM和 SUBSTR 函数一起得到错误提示信息,方便进行错误,特别是如果WHEN OTHERS异常处理器时更为方便。

    • SQLCODE  返回遇到的Oracle 错误号
    • SQLERRM  返回遇到的Oracle错误信息

    二、处理预定义例外

    对这种异常情况的处理,只需在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可。

    常见错误预定义的名称

    •     ACCESS_INTO_NULL(ORA-06530):引用对象类型变量的属性时,未对变量进行初始化;
    •     CASE_NOT_FOUND(ORA-06592):使用case-when结构时,未使用else子句,并且处理了不包含的case条件;
    •     COLLECTION_IS_NULL(ORA-06531):引用集合类型元素时,未对集合类型变量初始化;
    •     CURSOR_ALREADY_OPEN(ORA-06511):使用open命令打开已经处于打开状态的显式游标;
    •     DUL_VAL_ON_INDEX(ORA-00001):在唯一约束的列上插入重复的值时会触发;
    •     INVALID_NUMBER(ORA-01722):不能将字符转换为合理的数字时会触发;
    •     NO_DATA_FOUND(ORA-01403):select语句未返回行或引用未初始化的索引表元素;
    •     TOO_MANY_ROWS(ORA-01422):select into时,返回数据超过一行时即被触发;
    •     ZERO_DEVIDE(ORA-01476):除0异常;
    •     SUBSCRIPT_BEYOUND_COUNT(ORA-06533):使用数组类型是,下标超出元素范围;
    •     SUBSCRIPT_OUTSIDE_LIMIT(ORA-06532):使用嵌套表或Varry元素时,使用了负数作为下标;
    •     VALUE_ERROR(ORA-06502):赋值操作时,变量长度不足以容纳实际数据长度
    •     ROWTYPE_MISMATCH(ORA-06504):位游标变量赋值时,返回类型与游标定义类型不一致
    --例1:更新指定员工工资,如工资小于1500,则加100;
    DECLARE
       v_empno employees.employee_id%TYPE := &empno;
       v_sal   employees.salary%TYPE;
    BEGIN
       SELECT salary INTO v_sal FROM employees WHERE employee_id = v_empno;
       IF v_sal<=1500 THEN 
            UPDATE employees SET salary = salary + 100 WHERE employee_id=v_empno; 
            DBMS_OUTPUT.PUT_LINE(‘编码为‘||v_empno||‘员工工资已更新!‘);     
       ELSE
            DBMS_OUTPUT.PUT_LINE(‘编码为‘||v_empno||‘员工工资已经超过规定值!‘);
       END IF;
    EXCEPTION
       WHEN NO_DATA_FOUND THEN  
          DBMS_OUTPUT.PUT_LINE(‘数据库中没有编码为‘||v_empno||‘的员工‘);
       WHEN TOO_MANY_ROWS THEN
          DBMS_OUTPUT.PUT_LINE(‘程序运行错误!请使用游标‘);
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||‘—‘||SQLERRM);
    END;

    三、处理非预定义例外(exception_init)

    对于这类异常情况的处理,首先必须对非定义的ORACLE错误进行定义。步骤如下:

    1. 在PL/SQL 块的定义部分定义异常情况:
      <异常情况> EXCEPTION;
    2. 将系统异常转为用户定义异常:将其定义好的异常情况,与标准的ORACLE错误联系起来,使用EXCEPTION_INIT语句:
      PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>);
    --例2:删除指定部门的记录信息,以确保该部门没有员工。
     
    INSERT INTO departments VALUES(50, ‘FINANCE‘, ‘CHICAGO‘);
    DECLARE
       v_deptno departments.department_id%TYPE := &deptno;
       deptno_remaining EXCEPTION;--定义一个异常变量
       PRAGMA EXCEPTION_INIT(deptno_remaining, –2292); /* -2292 是违反一致性约束的错误代码 */
    BEGIN
       DELETE FROM departments WHERE department_id = v_deptno;
    EXCEPTION
       WHEN deptno_remaining THEN 
          DBMS_OUTPUT.PUT_LINE(‘违反数据完整性约束!‘);
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||‘—‘||SQLERRM);
    END;

    四、处理自定义例外(通过Raise )

    当与一个异常错误相关的错误出现时,就会隐含触发该异常错误。用户定义的异常错误是通过显式使用 RAISE 语句来触发。当引发一个异常错误时,控制就转向到 EXCEPTION块异常错误部分,执行错误处理代码。对于这类异常情况的处理,步骤如下:

    1. 在PL/SQL 块的定义部分定义异常情况:
      <异常情况> EXCEPTION;
      RAISE <异常情况>
    2. 在PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。
    --例3:更新指定员工工资,增加100;
     
    DECLARE
       v_empno employees.employee_id%TYPE :=&empno;
       no_result  EXCEPTION;-定义异常
    BEGIN
       UPDATE employees SET salary = salary+100 WHERE employee_id = v_empno;
       IF SQL%NOTFOUND THEN
          RAISE no_result;//触发异常
       END IF;
    EXCEPTION
       WHEN no_result THEN //捕捉异常
          DBMS_OUTPUT.PUT_LINE(‘你的数据更新语句失败了!‘);
       WHEN OTHERS THEN
          DBMS_OUTPUT.PUT_LINE(SQLCODE||‘—‘||SQLERRM);

    五、应用程序的异常处理。(通过Raise_Application_Error )

    调用DBMS_STANDARD(ORACLE提供的包)包所定义的RAISE_APPLICATION_ERROR过程,可以重新定义异常错误消息,它为应用程序提供了一种与ORACLE交互的方法。

    RAISE_APPLICATION_ERROR 的语法如下:

    RAISE_APPLICATION_ERROR(error_number,error_message,[keep_errors] );
    • error_number:从 –20,000 到 –20,999 之间的参数,
    • error_message:是相应的提示信息(< 2048 字节),
    • keep_errors:可选,如果keep_errors =TRUE ,则新错误将被添加到已经引发的错误列表中。如果keep_errors=FALSE(缺省),则新错误将替换当前的错误列表。

    例:创建一个函数get_salary, 该函数检索指定部门的工资总和,其中定义了-20991和-20992号错误,分别处理参数为空和非法部门代码两种错误:

    CREATE OR REPLACE FUNCTION get_salary(p_deptno NUMBER) #函数检索指定部门的工资总和
    RETURN NUMBER 
    AS
      v_sal NUMBER; #函数get_salary返回v_sal值
    BEGIN
      IF p_deptno IS NULL THEN
        RAISE_APPLICATION_ERROR(–20991, ’部门代码为空’); #用户定义的异常处理
      ELSIF p_deptno<0 THEN
        RAISE_APPLICATION_ERROR(–20992, ’无效的部门代码’);
      ELSE
        SELECT SUM(employees.salary) INTO v_sal FROM employees 
        WHERE employees.department_id=p_deptno;
        RETURN v_sal;
      END IF;

    调用函数

    DECLARE 
      V_salary NUMBER(7,2);
      V_sqlcode NUMBER;
      V_sqlerr VARCHAR2(512);
      Null_deptno EXCEPTION;  #定义异常情况
      Invalid_deptno EXCEPTION; #定义异常情况
      PRAGMA EXCEPTION_INIT(null_deptno,–20991);  #非预定义的异常,将它与oracle错误联系起来
      PRAGMA EXCEPTION_INIT(invalid_deptno, –20992); #非预定义的异常,将它与oracle错误联系起来
    BEGIN
      BEGIN
        V_salary :=get_salary(–10);
      EXCEPTION
        WHEN invalid_deptno THEN
          V_sqlcode :=SQLCODE;
          V_sqlerr  :=SQLERRM;
          INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr); #将错误SQLCODE及SQLERRM存入到表errlog中  
          COMMIT;
      END ;

    例:定义触发器,使用RAISE_APPLICATION_ERROR阻止没有员工姓名的新员式记录插入:

    CREATE OR REPLACE TRIGGER tr_insert_emp
    BEFORE INSERT ON employees
    FOR EACH ROW
    BEGIN
      IF :new.first_name IS NULL OR :new.last_name is null THEN
        RAISE_APPLICATION_ERROR(–20000,‘Employee must have a name.‘);
      END IF;

  • 相关阅读:
    福大软工1816 · 第六次作业
    福大软工1816 · 第五次作业
    BETA 版冲刺前准备
    Alpha 事后诸葛亮(团队)
    Alpha 答辩总结
    Alpha 冲刺 (10/10)
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
  • 原文地址:https://www.cnblogs.com/springsnow/p/9394889.html
Copyright © 2020-2023  润新知