有三种类型的异常错误:
1. 内部异常 ( Internally defined )异常
ORACLE内部异常有25个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发,内部异常包含异常名和异常代码和异常消息。
2. 预定义 ( Predefined )异常
即其他标准的ORACLE错误。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发,预定义异常只包含异常代码和异常消息,不包含异常名称。
3. 用户自定义(User-define) 异常
程序执行过程中,出现编程人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后显式地在程序中将其引发。
--内部异常的使用
例1:更新指定员工工资,如工资小于1500,则加100;
登录SCOTT用户
DECLARE
v_empno emp.empno%TYPE := '&empno';
v_sal emp.sal%TYPE:=0;
BEGIN
SELECT sal INTO v_sal FROM emp WHERE empno = v_empno;
IF v_sal<=1500 THEN
UPDATE emp SET sal = sal + 100 WHERE empno=v_empno;
DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已更新!');
ELSE
DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'员工工资已经超过规定值!');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('错误提示:'||SQLCODE||'---'||SQLERRM);
END;
/
--预定义异常的使用
例2:删除指定部门的记录信息,以确保该部门没有员工。
INSERT INTO dept VALUES(50, 'FINANCE', 'CHICAGO');
commit;
select * from dept;
DECLARE
v_deptno dept.deptno%TYPE := '&deptno';
deptno_remaining EXCEPTION;
PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);
/* -2292 是违反一致性约束的错误代码 */
BEGIN
DELETE FROM dept WHERE deptno = v_deptno;
EXCEPTION
WHEN deptno_remaining THEN
DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
/
--RAISE的使用
例3:更新指定员工工资,增加100;
DECLARE
v_empno emp.empno%TYPE :=&empno;
no_result EXCEPTION;
BEGIN
UPDATE emp SET sal = sal+100 WHERE empno = v_empno;
IF SQL%NOTFOUND THEN
RAISE no_result;
END IF;
EXCEPTION
WHEN no_result THEN
DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
END;
/
可能不是很多人知道 RAISE_APPLICATION_ERROR 的用途是什么,虽然从字面上已经猜到这个函数是干什么用的。平时用来测试的异常处理
我们都是通过dbms_output.put_line来输出异常信息,但是在实际的应用中,需要把异常信息返回给调用的客户端。
其实 RAISE_APPLICATION_ERROR 是将应用程序专有的错误从服务器端转达到客户端应用程序(其他机器上的SQLPLUS或者其他前台开发语言)
RAISE_APPLICATION_ERROR 的声明:
PROCEDURE RAISE_APPLICATION_ERROR( error_number_in IN NUMBER, error_msg_in IN VARCHAR2);
里面的错误代码和内容,都是自定义的。说明是自定义,当然就不是系统中已经命名存在的错误类别,是属于一种自定义事务错误类型,才调用此函数。error_number_in 之容许从 -20000 到 -20999 之间,这样就不会与 ORACLE 的任何错误代码发生冲突。error_msg_in 的长度不能超过 2k,否则截取 2k。
举个例吧:
declare
l_n number:=&n;
/* is_oushu exception; --是偶数
PRAGMA EXCEPTION_INIT(is_oushu, -20000);*/
begin
if mod(l_n,2)=0 then
RAISE_APPLICATION_ERROR(-20001, '是偶数');--如果是偶数则抛出异常
end if;
exception
when others
then dbms_output.put_line('wrong:'||sqlerrm);
end;
/
--用EXCEPTION_INIT来实现
declare
l_n number:=&n;
is_oushu exception; --是偶数
PRAGMA EXCEPTION_INIT(is_oushu, -20000);
begin
if mod(l_n,2)=0 then
raise is_oushu;
end if;
exception
when is_oushu
then dbms_output.put_line('错误'||sqlerrm);
end;
/
--用RAISE_APPLICATION_ERROR 自定义异常
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(emp.sal) INTO v_sal FROM emp
WHERE emp.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 ;
V_salary :=get_salary(20);
DBMS_OUTPUT.PUT_LINE('部门号为20的工资为:'||TO_CHAR(V_salary));
BEGIN
V_salary :=get_salary(NULL);
END ;
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(SQLCODE||'---'||SQLERRM);
END ;
/
EXCEPTION_INIT和RAISE_APPLICATION_ERROR的区别
EXCEPTION_INIT的特点
1.用来调用预定义异常和用户自定义异常
2.调用时已经存在异常名称
RAISE_APPLICATION_ERROR的特点
1.不需要预定义而直接抛出异常
2.不用定义异常名称