OraclePL/SQL相当处理

As we all
known,程序的不当一般分为两类:编写翻译错误和平运动作时不当。当中运维时不当被称之为十分。PL/SQL语句块中处理十分的一对即为分外处理部分。在非凡处理局地,能够钦赐当特定万分产生时所选取的动作。

PL/SQL有三种档次的不行:内置相当和用户自定义万分。

里头,内置格外又分为预约义万分和非预定义很是。

1、内置至极

首先试举壹例来投石问路。

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_CUCR-VSO本田UR-V :不合规指针操作(关闭已经倒闭的游标)
ZERO_DIVIDE :除数等于零
DUP_VAL_ON_INDEX :违反唯1性约束
ACCESS_INTO_NULL: 未定义对象
CASE_NOT_FOUND: CASE 中若未包括相应的 WHEN ,并且未有安装 ELSE 时
COLLECTION_IS_NULL: 集合成分未开始化
CURSER_ALREADY_OPEN: 游标已经打开
DUP_VAL_ON_INDEX: 唯一索引对应的列上有双重的值
INVALID_NUMBERubicon: 内嵌的 SQL 语句不能够将字符转换为数字
NO_DATA_FOUND: 使用 select into
未重返行,或应用索引表未开头化的成分时
SUBSCRIPT_BEYOND_COUNT:成分下标超过嵌套表或 VABMWX5RAY 的最大值
SUBSCRIPT_OUTSIDE_LIMIT: 使用嵌套表或 VA帕杰罗RAY 时,将下标内定为负数
VALUE_EPAJERORO兰德瑞鹰: 赋值时,变量长度不足以容纳实际数目
LOGIN_DENIED: PL/SQL 应用程序连接到 oracle
数据库时,提供了不得法的用户名或密码
NOT_LOGGED_ON: PL/SQL 应用程序在一贯不连接 oralce
数据库的场合下访问数据
PROGRAM_EOdysseyROEscort: PL/SQL 内部难题,恐怕供给重装数据字典& pl./SQL 系统包
ROWTYPE_MISMATCH: 宿主游标变量与 PL/SQL 游标变量的归来类型不般配
SELF_IS_NULL: 使用对象类型时,在 null 对象上调用对象方法
STORAGE_E本田UR-VROCRUISER: 运营 PL/SQL 时,超出内部存款和储蓄器空间
SYS_INVALID_ID: 无效的 ROWID 字符串
TIMEOUT_ON_RESOUGL450CE: Oracle 在等待财富时超时

others可以象征享有尤其,oracle预订义的相当在30000以内。

2、 用户自定义相当

普通,在自身的先后里,大概需求处理与所写程序相关的难题。例如,在上个语句块中,必要输入职员和工人编号。平日,希望职员和工人编号是正值。不过无意间,用户输入三个负数。不过,未有生出任何不当,因为变量v_empno被定义为数值类型。那时,你指望自定义11分来拍卖那种情况,那种类型的不行被称为用户自定义万分。在运用该特别以前,必须首先举办宣示。语法结构如下所示:

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_EHavalROEscort是oracle提供的1种奇特的放置进度,允许编制程序职员为特定应用程序成立有意义的错误消息。RAISE_APPLICATION_E卡宴RO福睿斯进程适用于未命名的用户定义万分。它担负将错误编号和不当文本关联起来,它的语法为:

     RAISE_APPLICATION_ERROR(error_number,error_message);

   
 error_number是与一定错误音信相关联的荒谬编号。这些号码的限定在-2099九到-20000之间。error_message是荒谬文本,最多含有204柒个字符。

     上例可修改为:

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_ERAV四ROKoleos进程,编制程序人士能够遵从与Oracle错误壹致的点子赶回错误音信。

四、 EXCEPTION_INIT

在上文内置至极中,预约义至极的个数其实是十分简单的,当程序抛出别样不在上述预订义范围内的不得了时,该如何捕捉呢?

比如说下例:

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

当部门编号输入拾时,大家来看望运营结果:

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;

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

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

PL/SQL procedure successfully completed.

可以平常捕捉错误!

五、 SQLCODE和SQLERRM

之所以Oracle错误都得以应用OTHE帕杰罗S格外处理程序进行捕获和拍卖,如下例所示:

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语句所造成的数据类型匹配难题。尽管那只是三个归纳地例子,但照旧恐怕会发生过多意外的周转错误。

本来,你永远不只怕理解程序执行时具有十分大可能率发生的运营错误,由此,最佳在自身的顺序中添加OTHE路虎极光S至极处理程序。为改善自身程序的不胜处理接口,Oracle提供了四个放置函数-SQLCODE和SQLECR-VRM-用于达成OTHE冠道S万分处理程序。SQLCODE函数会回到Oracle错误编号,SQLE科雷傲GL450M函数再次回到错误音信。

修改上例如下:

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;

如出1辙,当输入十看作机关编号时,看看输出:

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.

这么可捕捉任何运维时不当的一无所能编号和谬误音讯 

总结:

     壹> 预约义格外的错误代码有名称,譬如上文提到的NO_DATA_FOUNG

     2>
非预约义格外唯有错误代码,未有称谓,如上文提到的ora-022玖二。那时能够通过EXCEPTION_INIT编写翻译指令展开错误代码和称号的涉嫌。

     三>
当PL/SQL语句块的可进行部分出现有个别运营错误时,会抛出差异品种的可怜。可是,运转错误也可能发生在语句块的证明部分还是尤其处理部分。控制在那几个环境下尤其抛出办法的平整称为非凡传播。

     四>
当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;

 

相关文章