阅读准备事项

  添加外键关联:

ALTER TABLE dept_learn ADD CONSTRAINT pk_dept_deptid PRIMARY KEY (department_id);
ALTER TABLE emp_learn ADD CONSTRAINT fk_emp_dept_deptid FOREIGN KEY (department_id) REFERENCES dept_learn(department_id);

异常简介

   在PL/SQL块中捕获并处理异常,可以提高程序的健壮性,使得应用程序可以安全正常的运行。异常是一种PL/SQL标识符,它有预定义异常、非预定义异常和自定义异常三种类型。在PL/SQL块中,如果不捕获和处理异常,oracle会将错误传递到调用环境。

   本节学习目标:

  • 学会使用上面介绍的3种异常。
  • 学会使用异常处理函数。
  • 学会使用PL/SQL编译警告。
      
      异常使用语法:
      DECLARE statements;
      BEGIN
        statements;
      EXCEPTION
        WHEN exception1 [OR exception2 …] THEN
           statements;
        [WHEN exception3 [OR exception4 …] THEN
           statements;]
        [WHEN OTHERS THEN
           statements;]
      END;

捕捉并处理异常

预定义异常

   指由PL/SQL所提供的系统异常。oracle为开发人员提供了21个预定义异常(将在本节末尾一一列出),每个预定义异常对应一个特定的oracle错误,当PL/SQL块出现这些oracle错误时,会隐含的触发相应的预定义异常。

   示例:

DECLARE
   v_name emp_learn.first_name%TYPE;
BEGIN
   SELECT first_name INTO v_name FROM emp_learn WHERE department_id = &dno;
   dbms_output.put_line('雇员号'||&dno||'的名字为:'||v_name);
EXCEPTION
   WHEN NO_DATA_FOUND THEN
      dbms_output.put_line('不存在该部门!');
   WHEN TOO_MANY_ROWS THEN
      dbms_output.put_line('该部门有多个员工!');
   WHEN OTHERS THEN
      dbms_output.put_line('未知错误!');
END;
  • ###非预定义异常

非预定义异常用于处理与预定义异常无关的oracle错误。预定义异常只能处理21种oracle错误,而PL/SQL块可能还会遭遇其它oracle错误,此时可能需要用到非预定义异常了。

非预定义异常使用步骤:
  a)定义异常标识符。必须在定义部分定义异常标识符。
  b)在oracle错误号和异常之间建立关联。需要在定义部分引用伪过程EXCEPTION_INIT。
  c)捕捉并处理异常。

  示例:在此节的开始时,我们为emp_learn和dept_learn变建立了外键关联,当更新雇员的部门号时,部门号必须在dept_learn表中存在,否则会触发ORA-02291错误。
  

-- 触发ORA-02291错误
SQL> UPDATE emp_learn SET department_id=2000 WHERE employee_id = 198;
ORA-02291: 违反完整约束条件 (HR.FK_EMP_DEPT_DEPTID) - 未找到父项关键字
-- 使用非预定义异常处理ora-02291错误
DECLARE
   e_int EXCEPTION;
   PRAGMA EXCEPTION_INIT(e_int,-2291);
   v_name emp_learn.first_name%TYPE:=LOWER('&name');
   v_deptno dept_learn.department_id%TYPE:=&dno;    
BEGIN
   UPDATE emp_learn SET department_id=v_deptno WHERE LOWER(first_name) = v_name;
EXCEPTION
   WHEN e_int THEN
      dbms_output.put_line('该部门不存在!');
END;
  • ###自定义异常

在上面“使用非预定义异常处理ora-02291错误”的示例代码中,如果输入一个不存在的雇员的first_name,将不会更新到行数据,不会触发e_int这个非预定义异常,PL/SQL将不会给出任何提示信息。如果此时需要获取到某些信息,或者做某些操作的话,就需要用到自定义异常了。

使用步骤:
a)定义异常标识符。必须在定义部分定义。
b)主动触发异常。使用RAISE语句显式触发。
c)捕获并处理异常。

  示例:

DECLARE
   e_int EXCEPTION;
   e_int_norows EXCEPTION;
   PRAGMA EXCEPTION_INIT(e_int,-2291);
   v_name emp_learn.first_name%TYPE:=LOWER('&name');
   v_deptno dept_learn.department_id%TYPE:=&dno;    
BEGIN
   UPDATE emp_learn SET department_id=v_deptno WHERE LOWER(first_name) = v_name;
   IF SQL%NOTFOUND THEN
      RAISE e_int_norows;
   END IF;
EXCEPTION
   WHEN e_int THEN
      dbms_output.put_line('该部门不存在!');
   WHEN e_int_norows THEN
      dbms_output.put_line('该雇员不存在!');
END;

使用异常处理函数

   异常处理函数用于取得oracle错误号和错误消息,其中函数SQLCODE用于取得错误号,SQLERRM用于取得错误消息。当编写PL/SQL块时,通过在异常处理部分引用函数SQLCODE和SQLERRM,可以取得未预计到的oracle错误。通过使用内置过程RAISE_APPLICATION_ERROR,可以在建立子程序(过程、函数和包)时自定义错误号和错误消息。

  RAISE_APPLICATION_ERROR过程只适用于数据库子程序(过程、函数、包、触发器),语法:
  raise_application_error(error_number,message,[,{TRUE | FALSE}]);
  当第三个参数设置为TRUE,则错误会存放到先前错误堆栈,否则会替换先前所有错误。

示例:

DECLARE
   e_int EXCEPTION;
   PRAGMA EXCEPTION_INIT(e_int,-20000);
BEGIN
   DELETE FROM dept_learn WHERE department_id=&dno;
   IF SQL%NOTFOUND THEN
      raise_application_error(-20000,'该部门不存在!');
   END IF;
EXCEPTION 
   WHEN e_int THEN
      dbms_output.put_line('错误号:'||SQLCODE||',错误消息:'||SQLERRM);
   WHEN OTHERS THEN 
      dbms_output.put_line('others-错误号:'||SQLCODE||',错误消息:'||SQLERRM);
END;