PL/SQL 异常处理

一,异常处理说明

在使用PL/SQL进行编程时,难免会出现错误,出于“不想总是弹窗报错”、“想让报错信息更加明晰”或“想让报错更符合实际业务”等原因,我们将报错收集在异常处理部分集中特殊处理。
程序运行过程中的原因有很多,包括程序原本就有语法上的问题,或是数据有问题,或是出于业务方面考虑,用户需要设定一些从数据库角度虽然没有异常但是从业务角度认为异常的报错。
对于异常分类,ORACLE官方与ORACLE用户分别给出两种不同的理解方案,这两种方案只是出发点不同,不影响实际的使用。

二,异常处理分类

官方给出的分类是将异常分为预定义异常和自定义异常(错误编码异常与业务逻辑异常);
而用户则将异常分为系统异常(预定义异常,非预定义异常)和自定义异常。
在这里插入图片描述
异常处理的结构:
EXCEPTION
WHEN ERR_NAME1 THEN --ERR_NAME1:异常的名称
EXCEPT_SENTENCE1 --如何处理这个异常
WHEN ERR_NAME2 THEN
EXCEPT_SENTENCE2

WHEN OTHERS THEN
EXCEPT_SENTENCE
我们接下来从用户角度来分类异常

1.异常处理-预定义异常

预定义异常在使用时完全不需要用户声明,由ORACLE自行引发自行判定。
语法:
BEGIN
PLSQL_SENTENCE
EXCEPTION
WHEN ERR_NAME THEN
EXCEPT_SENTENCE
END;
实例:
–为方便,使用emp表,以下都是
DECLARE
V_ENAME VARCHAR2(15);
BEGIN
–emp表是没有783这个客户编号的,所以会找不到数据
SELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=783;
DBMS_OUTPUT.PUT_LINE(V_ENAME);
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;
在这里插入图片描述

说明:预定义异常是有错误名称,错误信息,错误编码的;所以想给一些有名称的异常一些特殊的处理可以这样;但实际工作中,基本都是OTHERS,将异常信息赋给一个变量插入日志表中。

2.异常处理-非预定义异常

语法:
DECLARE
ERR_NAME EXCEPTION;
PRAGMA EXCEPTION_INIT(ERR_NAME,ERR_CODE);
BEGIN
PLSQL_SENTENCE
EXCEPTION
WHEN ERR_NAME THEN
EXCEPT_SENTENCE
END;
实例:
因为非预定异常是没有错误名称,只有错误信息和错误编码,所以我们需要给它定义一个错误名称,这样才能引用到它。
在这里插入图片描述
在这里插入图片描述
我们可以发现该异常的编码是-00937。所以:
DECLARE
V_DEPTNO NUMBER;
V_SUMSAL NUMBER;
NOT_GROUP EXCEPTION; --声明一个错误名称
PRAGMA EXCEPTION_INIT(NOT_GROUP,-00937); --将错误名称与错误编码关联起来
BEGIN
SELECT DEPTNO,SUM(SAL) INTO V_DEPTNO,V_SUMSAL FROM EMP;
EXCEPTION
WHEN NOT_GROUP THEN
DBMS_OUTPUT.PUT_LINE(‘没有分组’);
END;
在这里插入图片描述
说明:因为非预定义异常是没有名称的,所以要想根据名称调用它需要声明一个错误名称,并将这个错误名称和异常编号关联起来。

3.异常处理-自定义异常

自定义异常就是什么都没有的了,不仅要给它取名,还要给它一个编号,以及错误信息;
语法:
DECLARE
ERR_NAME EXCEPTION
BEGIN
IF<CONDITION_EXCEPTION1> THEN
RAISE ERR_NAME;
END IF;
PLSQL_SENTENCE
EXCEPTION
WHEN ERR_NAME THEN
EXCEPT_SENTENCE
END;
实例:
事件:公司因收益不好,需要辞退一些员工,但SMITH是公司的元老,帮过老板很多事,不能将他辞退。
为了防止人事错误操作,将SMITH这个名字设为异常,要辞退时会弹窗提示;
DECLARE
V_ENAME VARCHAR2(20):=‘&请指定姓名’;
–声明一个异常名称
SMITH EXCEPTION;
–将异常名称和异常编码关联起来,编码限制在-20001到-20999之间
PRAGMA EXCEPTION_INIT(SMITH,-20005);
BEGIN
IF V_ENAME=‘SMITH’ THEN
/* RAISE smith;*/
–给这个异常设置弹窗提示信息
RAISE_APPLICATION_ERROR(-20005,‘SMITH为你挡过子弹挨过刀,你要辞退他?’);
ELSE
DELETE FROM EMP WHERE ENAME=V_ENAME;
DBMS_OUTPUT.PUT_LINE(V_ENAME||‘不干了’);
END IF;
EXCEPTION
WHEN smith THEN
DBMS_OUTPUT.PUT_LINE(‘SMITH劳苦功高,不该走’);
RAISE;
END;
在这里插入图片描述
在这里插入图片描述
我们可以发现,如果要辞退SMITH会引发异常。
试试其他人:
在这里插入图片描述
在这里插入图片描述
我们可以发现,如果是别人的话,直接就辞退了。

三,捕获错误信息

普及函数:
SQLERRM:会返回异常信息
SQLCODE:会返回一个返回码,0是没有异常,其他的数字都代表异常,其中100是没有数据;
实例
DECLARE
V_ENAME VARCHAR2(30);
–定义两个变量来存放异常信息
V_ERRM VARCHAR2(100);
V_CODE VARCHAR2(10);
BEGIN
–因为没有724这个员工编号,异常是必然发生的
SELECT ENAME INTO V_ENAME FROM EMP WHERE EMPNO=724;
DBMS_OUTPUT.PUT_LINE(V_ENAME);
EXCEPTION
WHEN OTHERS THEN
–将异常信息赋给变量V_ERRM
V_ERRM:=SQLERRM;
–将返回码赋给变量V_CODE
V_CODE:=SQLCODE;
DBMS_OUTPUT.PUT_LINE(V_ERRM||‘—’||V_CODE);
END;
在这里插入图片描述
注:在实际工作中,我们一般都是将异常信息插入日志表中的。这也很简单,就是将各个数据用变量来承载,在调用时直接将变量当做输入参数就行了。(有的是编写存储过程将数据插入日志表,这样只需要在存储过程中调用存储过程就行了;而有的会在存储过程中直接用INSERT INTO将数据插入日志表。)都行,但编写存储过程会更方便,代码更优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值