目录
PL/SQL异常
即运行时发生的错误。
异常的触发:
- 发生一个oracle错误时
- 使用RAISE子句显式触发
处理异常:
- 处理机截获
- 在调用环境中异常传播
例子:
DECLARE
v_ename emp.ename%TYPE;
v_empno NUMBER(4) := 7369;
BEGIN
select ename
into v_ename
from emp
where empno=v_empno;
dbms_output.put_line(v_ename);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('others');
END;
正常运行,输出SMITH
当修改为不存在的员工号时
DECLARE
v_ename emp.ename%TYPE;
v_empno NUMBER(4) := 736;
BEGIN
select ename
into v_ename
from emp
where empno=v_empno;
dbms_output.put_line(v_ename);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('others');
END;
没有这个数据,输出others;如果没有异常处理的话,程序则会终止掉。
异常类型
异常 | 描述 | 处理 |
Oracle服务器预定义异常 | Oracle中有名字的错误 | 不需声明,可以由Oracle服务器隐式地触发 |
Oracle 服务器非预定义的异常 | 其它所有非标准的Oracle服务器错误 | 在声明部分声明,可以由Oracle服务器隐式地触发 |
用户定义异常 | 由开发者决定的异常情形 | 在声明部分声明,由程序显式地触发 |
语法:
EXCEPTION
WHEN exception1 [or exception2...] THEN
statement;statement;...
WHEN exception3 [or exception4...]THEN
statement;statement;...
[WHEN OTHERS THEN
statement;statement;...]
注意:
- 在异常部分WHEN子句没有数量限制
- WHEN OTHERS 是最后一 个子句
- 异常处理部分从关键字EXCEPTION开始
- 当异常抛出后,控制无条件转到异常处理部分
- 在离开块之前只能执行一种异常处理
当程序出了异常的时候,程序正常的流程就不再走了。
预定义异常
异常情况名 | 错误代码 | 描述 |
DUP_VAL_ON_INDEX | 0RA-00001 | 试图更新或插入重复记录 |
INVALID_CURSOR | 0RA-01001 | 非法游标操作 |
INVALID_NUMBER | 0RA-01722 | 字符串向数字转换失败 |
NO_DATA_FOUND | ORA-01403 | 执行的SELECT没有查到数据 |
TOO_MANY_ROWS | ORA-01427 | 未使用游标,SELECT语句返回了多行数据 |
VALUE_ERROR | 0RA-06502 | 出现数字、数据转换、字符串或限制型错误 |
ZERO_DIVIDE | ORA-01476 | 被零除 |
非预定义异常
Oracle错误但是只有代码没有名字。
DECLARE
e_emp_cons EXCPTION;
PRAGMA EXCEPTION_ INIT(e_emp_cons,-00001);
捕获异常的函数
- SQLCODE:返回错误代码
- SQLERRM:返回错误值相关联的信息
例子
DECLARE
v_ename emp.ename%TYPE;
v_empno NUMBER(4) := 736;
BEGIN
select ename
into v_ename
from emp
where empno=v_empno;
dbms_output.put_line(v_ename);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
END;
但是在实际中,不会这样输出错误,而是会使用一个异常表来记录
CREAT TABLE ERRORS(
objname VARCAHR2(100),
eDATE DATE,
SQLCODE NUMBER(6),
SQLERRM VARCHAR2(200)
)
那么代码可以改成
DECLARE
v_ename emp.ename%TYPE;
v_empno NUMBER(4) := 736;
verrcode NUMBER(6);
v_errmsg VARCHAR2(200);
BEGIN
select ename
into v_ename
from emp
where empno=v_empno;
dbms_output.put_line(v_ename);
EXCEPTION
WHEN OTHERS THEN
verrcode := SQLCODE;
v_errmsg := SQLERRM
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
VALUES('',sysdate,verrcode,v_errmsg)
END;
这样就可以把初始值放在一个表中。
用户定义的异常
在oracle中不算错误但是我们觉得是错误。需要手动用RAISE子句触发。
例子
DECLARE
e_ too_ many EXCEPTION;
BEGIN
update emp
set sal= 5000
where deptno=&xp_ deptno;
if SOL %ROWCOUNT >2 then
RAISE e_ too_ many;
end if;
EXCEPTION
when e_ too_ many then
dbms_ output.put_ line('涨工资人数'|| SQL%ROWCOUNT||'人,太多了);
rollback;
End;
异常传递
异常如果没有做处理,会向上一次传。
Raise_Application_Error过程
模拟出现一个错误,产生一个类似于异常的对话框并终止程序,错误编号在-20000~-20999之间,错误消息长度最大为2048字节
DECLARE
e_ name exception;
pragma exception_ init(e_ name, 20202);
BEGIN
delete from emp where deptno=90;
if SQL%NOTFOUND then
Raise_ Application_ Error(- 20202,’部门不存在);
end if;
EXCEPTION
when e_ name then
dbms_ output. put line(sqlcode);
dbms_ output.put line(sqlerrm);
END;
这个代码的作用是删除人员时发现没有这个部门,会弹出一个对话框并终止程序,提示部门不存在。