OraclePL/SQL异常处理

As we all
known,程序的缪一般分为两类:编译错误以及运转时误。其中运行时误让称为大。PL/SQL语句块被处理好的片就为好处理部分。在挺处理局部,可以指定当特定异常来时所采用的动作。

PL/SQL有点儿种类型的异常:内置异常以及用户从定义格外。

其中,内置异常而分为预定义异常及无预定义异常。

平、内置异常

率先试举无异于章来废弃砖引玉。

DECLARE
   v_ename varchar2(10);
   v_empno number(4) := &v_empno;
BEGIN
   SELECT ename
     INTO v_ename
   FROM EMP
   WHERE empno = v_empno;
   DBMS_OUTPUT.PUT_LINE('Employee name is '||v_ename);
END;

该语句块通过输入员工的号来得起员工的真名。当输入的员工编号是时时,输出员工姓名,当员工编号不存在时时,会产生运行错误。如下所示:

SQL> /
Enter value for v_empno: 7788 
Employee name is SCOTT              -->> 输入的员工编号存在,输出员工姓名

PL/SQL procedure successfully completed.

SQL> /
Enter value for v_empno: 1234
DECLARE
*
ERROR at line 1:
ORA-01403: no data found            -->> 输入的员工编号不存在,报运行时错误
ORA-06512: at line 5

 由此可见,编译器无法检测运行错误。为在先后中处理这种类型的荒唐,必须上加十分处理部分。异常处理局部的语法结构如下:

EXCEPTION
       WHEN EXCEPTION_NAME THEN
             ERROR-PROCESSING STATEMENTS;

以告知句子块被,异常处理局部在可尽有后,上例可改如下:

DECLARE
   v_ename varchar2(10);
   v_empno number(4) := &v_empno;
BEGIN
   SELECT ename
     INTO v_ename
   FROM EMP
   WHERE empno = v_empno;
   DBMS_OUTPUT.PUT_LINE('Employee name is '||v_ename);
EXCEPTION
   WHEN NO_DATA_FOUND THEN
   DBMS_OUTPUT.PUT_LINE('There is no such employee');
END;

采取好处理局部,可以教程序能够正常了,而休是畸形终止。同时,输出结果更加面向用户,而非是编程人员。

上述NO_DATA_FOUND即为Oracle预定义异常。

下面列有一部分科普的预定义异常:

TOO_MANY_ROWS : SELECT INTO返回多实行
INVALID_CURSOR :非法指针操作(关闭已经关门的游标)
ZERO_DIVIDE :除数等于零
DUP_VAL_ON_INDEX :违反唯一性约束
ACCESS_INTO_NULL: 未定义对象
CASE_NOT_FOUND: CASE 中要不包含相应的 WHEN ,并且没有设置 ELSE 时
COLLECTION_IS_NULL: 集合元素未初始化
CURSER_ALREADY_OPEN: 游标已经打开
DUP_VAL_ON_INDEX: 唯一索引对应的列上有重的价
INVALID_NUMBER: 内嵌的 SQL 语句不能够以字符转换为数字
NO_DATA_FOUND: 使用 select into
未回到行,或应用索引表未初始化的素时
SUBSCRIPT_BEYOND_COUNT:元素下标超过嵌套表或 VARRAY 的最好大值
SUBSCRIPT_OUTSIDE_LIMIT: 使用嵌套表或 VARRAY 时,将下标指定为负数
VALUE_ERROR: 赋值时,变量长度不足以容纳实际数目
LOGIN_DENIED: PL/SQL 应用程序连接到 oracle
数据库时,提供了未科学的用户称或密码
NOT_LOGGED_ON: PL/SQL 应用程序在无连接 oralce
数据库的情状下访数
PROGRAM_ERROR: PL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包
ROWTYPE_MISMATCH: 宿主游标变量和 PL/SQL 游标变量的回来路不兼容
SELF_IS_NULL: 使用对象类型时,在 null 对象及调用对象方法
STORAGE_ERROR: 运行 PL/SQL 时,超出内存空间
SYS_INVALID_ID: 无效的 ROWID 字符串
TIMEOUT_ON_RESOURCE: Oracle 在等候资源时超过时

others可以象征享有特别,oracle预定义的那个在20000缘内。

亚、 用户从定义格外

日常,在大团结之次序里,也许得处理以及所勾画程序相关的题材。例如,在上个语词块被,需要输入员工编号。通常,希望员工编号是在。但是无意间,用户输入一个负数。但是,没有发任何不当,因为变量v_empno被定义为数值类型。这时,你期望由定义格外来拍卖这种状况,这种类型的杀被誉为用户从定义格外。在利用该特别之前,必须首先进行宣示。语法结构如下所示:

DECLARE
     exception_name EXCEPTION;
BEGIN
     …
     IF  CONDITION THEN
          RAISE exception_name;
     ELSE
          …
     END IF;
EXCEPTION
     WHEN exception_name THEN
           ERROR-PROCESSING STATEMENTS;
END;

故而上例可改也:

DECLARE
   v_ename varchar2(10);
   v_empno number(4) := &v_empno;
   e_invalid_no exception;
BEGIN
   IF v_empno < 0 THEN
        RAISE e_invalid_no;    -->> 注意:RAISE语句应该与IF语句一起使用,否则,每次执行时,执行权都会转到该语句块的异常处理部分
   ELSE
      SELECT ename
         INTO v_ename
      FROM EMP
      WHERE empno = v_empno;
      DBMS_OUTPUT.PUT_LINE('Employee name is '||v_ename);
   END IF;
EXCEPTION
   WHEN e_invalid_no THEN
   DBMS_OUTPUT.PUT_LINE('Employee number can not be negative');
END;

三、RAISE_APPLICATION_ERROR

     RAISE_APPLICATION_ERROR是oracle提供的平种非常之放置过程,允许编程人员为特定应用程序创建有含义的错误信息。RAISE_APPLICATION_ERROR过程适用于无命名的用户定义格外。它担负用错误编号和错文本关联起来,它的语法为:

     RAISE_APPLICATION_ERROR(error_number,error_message);

   
 error_number是暨一定错误信息相关联的错误编号。这个编号的限制以-20999到-20000里。error_message是不对文本,最多含2048只字符。

     上例可改也:

DECLARE
   v_ename varchar2(10);
   v_empno number(4) := &v_empno;
BEGIN
   IF v_empno < 0 THEN
        RAISE_APPLICATION_ERROR(-20000,'Employee number can not be negative');
   ELSE
      SELECT ename
         INTO v_ename
      FROM EMP
      WHERE empno = v_empno;
      DBMS_OUTPUT.PUT_LINE('Employee name is '||v_ename);
   END IF;
END;

当输入的职工编号为负数时,运行结果如下所示:

SQL> /
Enter value for v_empno: -1234
DECLARE
*
ERROR at line 1:
ORA-20000: Employee number can not be negative
ORA-06512: at line 6

借助于RAISE_APPLICATION_ERROR过程,编程人员能够以以及Oracle错误一致的主意回错误信息。

四、 EXCEPTION_INIT

于上文内置异常中,预定义异常的个数其实是格外简单的,当次抛来其他非以上述预定义范围外之杀时,该怎么捕捉呢?

诸如下例:

DECLARE
   v_deptno  number(2) := &v_deptno;
BEGIN
   DELETE FROM dept
    WHERE deptno= v_deptno;
END;

当部门编号输入10时,我们来探运行结果:

SQL> /
Enter value for v_deptno: 10
DECLARE
*
ERROR at line 1:
ORA-02292: integrity constraint (SCOTT.FK_DEPTNO) violated - child record found
ORA-06512: at line 4

违背父键约束,但是,我们什么样捕捉此种错误吧?在此地,我们得用到EXCEPTION_INIT。

使用EXCEPTION_INIT指令,可以拿某Oracle错误编号和用户定义格外的称谓建立涉。EXCEPTION_INIT指令出现于语句块的扬言部分,如下所示:

DECLARE
      exception_name EXCEPTION;
      PRAGMA EXCEPTION_INIT(exception_name,error_code);

只顾,用户定义格外的宣示起于所利用的EXCEPTION_INIT指令之前,EXCEPTION_INIT指令有少只参数:exception_name和error_code。exception_name是蛮的称呼,error_code是意在以及该特别建立涉的Oralce错误编号。

上例可改为:

DECLARE
   v_deptno  number(2) := &v_deptno;
   e_child_exists EXCEPTION;
   PRAGMA EXCEPTION_INIT(e_child_exists,-2292);
BEGIN
   DELETE FROM dept
    WHERE deptno= v_deptno;
EXCEPTION
   WHEN e_child_exists THEN
     DBMS_OUTPUT.PUT_LINE('Delete employees for No.'||v_deptno||' dept first');
END;

同将部门编号输入为10,来探望结果:

SQL> /
Enter value for v_deptno: 10
Delete employees for No. 10 dept frist

PL/SQL procedure successfully completed.

可健康捕捉错误!

五、 SQLCODE和SQLERRM

故而Oracle错误还足以采用OTHERS异常处理程序进行捕获和处理,如下例所示:

DECLARE
  v_deptno number(4) := &v_deptno;
  v_dname  varchar2(5);
  v_loc    varchar2(10);
BEGIN
  SELECT dname,loc
    INTO v_dname,v_loc
    FROM dept
  WHERE deptno = v_deptno;
  DBMS_OUTPUT.PUT_LINE(v_dname||','||v_loc);
EXCEPTION
  WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE('An error has occurred');
END;

当输入10当机构编号的价值经常,我们来探望输出:

SQL> /
Enter value for v_deptno: 10
An error has occurred

PL/SQL procedure successfully completed.

上述输出说明,在程序运行时发出一个误。如果你对表结构和数量不是老熟稔的话,你特别为难掌握此似是而非是呀,以及是什么原因造成错误产生的。也许在运行时,dept表中无存在对应之单位编号,或者SELECT
INTO语词所导致的数据类型匹配问题。尽管就只有是一个简练地例子,但仍可能会见有多飞的运作错误。

理所当然,你永远无法理解程序执行时有或有的运作错误,因此,最好于协调的程序中补充加OTHERS异常处理程序。为改良自己程序的挺处理接口,Oracle提供了有限独放置函数-SQLCODE和SQLERRM-用于贯彻OTHERS异常处理程序。SQLCODE函数会返回Oracle错误编号,SQLERRM函数返回错误信息。

改及例如下:

DECLARE
  v_deptno number(4) := &v_deptno;
  v_dname  varchar2(5);
  v_loc    varchar2(10);
BEGIN
  SELECT dname,loc
    INTO v_dname,v_loc
    FROM dept
  WHERE deptno = v_deptno;
  DBMS_OUTPUT.PUT_LINE(v_dname||','||v_loc);
EXCEPTION
  WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE(SQLCODE||chr(10)||SQLERRM);  -->> chr(10)代表回车键
END;

如出一辙,当输入10看成机构编号时,看看输出:

SQL> / 
Enter value for v_deptno: 10
-6502
ORA-06502: PL/SQL: numeric or value error: character string buffer too
small

PL/SQL procedure successfully completed.

如此这般可捕捉任何运行时左的谬误编号和错误信息 

总结:

     1> 预定义异常的错误代码有号,譬如上文提到的NO_DATA_FOUNG

     2>
非预定义异常只生错代码,没有称,如上文提到的ora-02292。这时可以通过EXCEPTION_INIT编译指令进行错误代码和名的涉嫌。

     3>
当PL/SQL语句块的不过实行有出现有运行错误时,会弃来不同档次的老大。但是,运行错误吗恐怕发生在语句块的扬言部分要特别处理局部。控制在这些环境下充分抛来方的规则称为大传播。

     4>
当PL/SQL语句块的声明部分还是很处理局部出现运行错误时,该语句块的深处理部分不克捕获此桩错误。如果非设有外部语句块,该程序执行会停止,并拿执行权转至主机环境。如果存在外部语句块,该特别会应声传播及表面语句块。如下例所示:

--outer block
BEGIN
   --inner block
   DECLARE
      v_test CHAR(3) := 'ABC';
   BEGIN
      v_test := '1234';
      DBMS_OUTPUT.PUT_LINE('v_test: '||v_test);
   EXCEPTION
      WHEN INVALID_NUMBER OR VALUE_ERROR THEN
          v_test := 'ABCD';
          DBMS_OUTPUT.PUT_LINE('An error has occurred in the inner block');
   END;
EXCEPTION
   WHEN INVALID_NUMBER OR VALUE_ERROR THEN
       DBMS_OUTPUT.PUT_LINE('An error has occurred in the program');
END;

当尽时,得到如下输出:

SQL> /
An error has occurred in the program

PL/SQL procedure successfully completed.

末尾试举无异于规章练练思维:

DECLARE
   my_error1 EXCEPTION;
   PRAGMA EXCEPTION_INIT(my_error1, -20001);
   my_error2 EXCEPTION;
   PRAGMA EXCEPTION_INIT(my_error2, -20002);
BEGIN
  IF 1=2  THEN
    raise_application_error(-20001,'err_1');
  ELSE
    raise_application_error(-20002,'err_2');
  END IF;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('Not found');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('More data');
  WHEN MY_ERROR1 THEN
    dbms_output.put_line('This is a err_1 test');
  WHEN MY_ERROR2 THEN
    dbms_output.put_line('This is a err_2 test');
END;

 

相关文章