PL/SQL编程整理4 -- 例外

本文介绍PL/SQL中的异常处理机制,包括预定义、非预定义及用户自定义异常的定义与处理方式。通过实例展示了不同类型的异常触发及其处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异常情况处理(EXCEPTION)是用来处理正常执行过程中未预料的事件,程序块的异常处理预定义的错误和自定义错误,由于PL/SQL程序块一旦产生异常而没有指出如何处理时,程序就会自动终止整个程序运行.

有三种类型的异常错误:

1.  预定义 ( Predefined )错误

ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发。

2.  非预定义 ( Predefined )错误

即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发。

3.  用户定义(User_define) 错误

程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。

 

1.1.1   预定义例外

预定义说明的部分 ORACLE 异常错误

错误号

异常错误信息名称

说明

ORA-0001

Dup_val_on_index

试图破坏一个唯一性限制

ORA-0051

Timeout-on-resource

在等待资源时发生超时

ORA-0061

Transaction-backed-out

由于发生死锁事务被撤消

ORA-1001

Invalid-CURSOR

试图使用一个无效的游标

ORA-1012

Not-logged-on

没有连接到ORACLE

ORA-1017

Login-denied

无效的用户名/口令

ORA-1403

No_data_found

SELECT INTO没有找到数据

ORA-1422

Too_many_rows

SELECT INTO 返回多行

ORA-1476

Zero-divide

试图被零除

ORA-1722

Invalid-NUMBER

转换一个数字失败

ORA-6500

Storage-error

内存不够引发的内部错误

ORA-6501

Program-error

内部错误

ORA-6502

Value-error

转换或截断错误

ORA-6504

Rowtype-mismatch

缩主游标变量与 PL/SQL变量有不兼容行类型

ORA-6511

CURSOR-already-OPEN

试图打开一个已存在的游标

ORA-6530

Access-INTO-null

试图为null 对象的属性赋值

ORA-6531

Collection-is-null

试图将Exists 以外的集合( collection)方法应用于一个null pl/sql 表上或varray

ORA-6532

Subscript-outside-limit

对嵌套或varray索引得引用超出声明范围以外

ORA-6533

Subscript-beyond-count

对嵌套或varray 索引得引用大于集合中元素的个数.

   

1、  case_no_found

编写case语句时,如果在when字句中没有包含必须的条件分支时,就会触发此例外,例如:

Declare

      V_sal emp.sal%type

Begin

      Select sal into v_sal from emp where ename=’SCOTT’; -- 如果返回3000

      Case

      When v_sal < 1000 then

            Update emp set sal=sal+100 where ename=’SCOTT’;

      When v_sal < 2000 then

            Update emp set sal=sal+200 where ename=’SCOTT’;

      End case;

      Exception

            When case_not_found then

            Dbms_output.put_line(‘case语句没有与’||v_sal||’相匹配的条件’);

End ;

 

2、  cursor_already_open

当重新打开已经打开的游标时,会触发该例外

Declare

     Cursor emp_cursor is select ename,sal from emp;

Begin

     Open emp_cursor;

     For emp_record in emp_cursor loop

           Dbms_output.put_line(emp_record.ename);

     End loop;

     Exception

           When cursor_already_open then

               Dbms_output.put_line(‘游标已经打开’);

End;

 

3、  dup_val_on_index

在唯一索引所对应的列上插入重复值时,会触发该例外。

4、  invalid_cursor

当试图在不合法的游标上执行操作时,会触发该例外,例如:试图从没有打开的游标提取数据或是关闭没有打开的游标。

5、  invalid_number

当输入的数据有误时,会触发该例外

6、  no_data_found

当执行select into 没有返回行时,就会触发该例外

7、  too_many_rows

        当执行select into语句时,如果返回超过了一行数据时,则会触发该例外

8、  zero_divide

当被0除时,则会触发该例外

9、  value_error

当在执行赋值操作时,如果变量的长度不足以容纳实际数据时,则会触发该例外

 

1.1.2   非预定义例外

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

1.       PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;

 

2.       将其定义好的异常情况,与标准的ORACLE错误联系起来,使用EXCEPTION_INIT语句:

PRAGMA EXCEPTION_INIT(<异常情况>, <错误代码>)

 

3.       PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

 

1删除指定部门的记录信息,以确保该部门没有员工。

INSERT INTO dept VALUES(50, ‘FINANCE’, ‘CHICAGO’);

 

DECLARE

   v_deptno dept.deptno%TYPE :=&deptno;

   e_deptno_remaining EXCEPTION;

   PRAGMA EXCEPTION_INIT(e_deptno_remaining, -2292);

   /* -2292 是违反一致性约束的错误代码 */

BEGIN

   DELETE FROM dept WHERE deptno=v_deptno;

EXCEPTION

   WHEN e_deptno_remaining THEN

      DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');

   WHEN OTHERS THEN

      DBMS_OUTPUT.PUT_LINE('发生其它错误!');

END;

 

1.1.3   自定义例外

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

    对于这类异常情况的处理,步骤如下:

1.  PL/SQL 块的定义部分定义异常情况:

<异常情况>  EXCEPTION;

 

2.  RAISE <异常情况>

 

PL/SQL 块的异常情况处理部分对异常情况做出相应的处理。

Declare

-- 定义一个例外

Myex exception;

Begin

Update emp set sal=sal+100 where empno=spNo;

-- sql%notfound 没有执行update

If sql%notfound then

-- 触发例外

Raise myex;

End if;

Exception

When myex then

Dbms_output.put_line(‘没有更新任何用户’);

End ;

 

1.1.4   自定义例外处理

调用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(缺省),则新错误将替换当前的错误列表。

 

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

CREATE TABLE errlog(

    Errcode NUMBER,

    Errtext CHAR(40));

 

CREATE OR REPLACE FUNCTION get_salary (p_deptno NUMBER)

    RETURN NUMBER AS

    V_sal NUMBER;

BEGIN

    IF p_deptno IS NULL THEN

        RAISE_APPLICATION_ERROR(-20991, ’部门代码为空’);

    ELSIF p_deptno<0 THEN

        RAISE_APPLICATION_ERROR(-20992, ’无效的部门代码’);

    ELSE

        SELECT SUM(sal) INTO v_sal FROM EMP WHERE deptno=p_deptno;

        RETURN V_sal;

    END IF;

END;

 

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);

    PRAGMA EXCEPTION_INIT(invalid_deptno, -20992);

BEGIN

    V_salary :=get_salary(10);

    DBMS_OUTPUT.PUT_LINE(’10号部门工资:’||TO_CHAR(V_salary));

 

    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);

            COMMIT;

    END inner1;

 

    V_salary :=get_salary(20);

    DBMS_OUTPUT.PUT_LINE(’20号部门工资:’||TO_CHAR(V_salary));

 

    BEGIN

        V_salary :=get_salary(NULL);

    END inner2;

 

    V_salary :=get_salary(30);

    DBMS_OUTPUT.PUT_LINE(’30号部门工资:’||TO_CHAR(V_salary));

 

    EXCEPTION

        WHEN null_deptno THEN

            V_sqlcode :=SQLCODE;

            V_sqlerr :=SQLERRM;

            INSERT INTO errlog(errcode, errtext) VALUES(v_sqlcode, v_sqlerr);

            COMMIT;

    WHEN OTHERS THEN

DBMS_OUTPUT.PUT_LINE('发生其它错误!');

END outer;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值