当前位置: 代码迷 >> SQL >> PL/SQL_处置例外1(预定义例外)
  详细解决方案

PL/SQL_处置例外1(预定义例外)

热度:58   发布时间:2016-05-05 11:37:32.0
PL/SQL_处理例外1(预定义例外)
当开发PL/SQL应用程序时,为了提高应用程序的健壮性,开发人员必须考虑PL/SQL程序可能出现的各种错误,并进行相应的错误处理。如果不进行错误处理,在出现运行错误时,会终止PL/SQL程序的运行,并显示错误信息。在编写PL/SQL程序时,通过使用例外(Exception)可以处理运行错误。
例外分类
为了处理PL/SQL应用程序的各种错误,开发人员可以使用各种类型的例外。Oracle提供了预定义例外、非预定义例外和自定义例外等三种例外类型。
在PL/SQL块中捕捉并处理例外需要使用额外的处理部分来完成,例外处理部分是 关键字EXCEPTION开始的,语法如下所示:
EXCEPTIONWHEN exception1 [OR exception2...] THENstatement1;statement2;...[WHEN exception3 [OR exception4...] THENstatement1;statement2;...[when OTHERS THENstatement1;statement2;...
示例:
DECLARE  v_ename emp.ename%TYPE;BEGIN  SELECT ename INTO  v_ename FROM emp WHERE empno = &NO;  dbms_output.put_line('雇员名:' || v_ename);  EXCEPTION    WHEN NO_DATA_FOUND THEN      dbms_output.put_line('雇员号不存在,请核实雇员名');END;

处理预定义例外

预定义例外是指由PL/SQL所提供的系统例外。当PL/SQL应用程序违反了Oracle规则或系统限制时,则会隐含地触发一个内部例外。
1、常用预定义例外
(1)ACCESS_INTO_NULL
该例外对应于ORA-06530错误。当开发对象类型应用时,在引用对象属性之前,必须首先初始化对象。
建立对象类型:
CREATE TYPE emp_type AS object(  NAME VARCHAR2(10),  sal NUMBER(6,2));
捕捉并处理该例外的示例如下:
DECLARE  v_emp emp_type;  --v_emp emp_type := emp_type('',0);BEGIN  v_emp.name := '张三';  v_emp.sal := 1000;  EXCEPTION    WHEN ACCESS_INTO_NULL THEN      dbms_output.put_line('首先初始化emp');END;
(2)CASE_NOT_FOUND
该例外对应于ORA-06592错误。当在PL/SQL块中编写CASE语句时,如果在WHEN子句中没有包含必须的条件分支,并且没有包含ELSE子句,就会隐含地触发CASE_NOT_FOUND例外。
DECLARE  v_sal emp.sal%TYPE;BEGIN  SELECT sal INTO v_sal FROM emp WHERE empno = &NO;  CASE    WHEN v_sal < 1000 THEN      UPDATE emp SET sal = sal + 100 WHERE empno = &NO;    WHEN v_sal < 2000 THEN      UPDATE emp SET sal = sal + 150 WHERE empno = &NO;    WHEN v_sal < 3000 THEN      UPDATE emp SET sal = sal + 200 WHERE empno = &NO;  END CASE;  EXCEPTION    WHEN CASE_NOT_FOUND THEN      dbms_output.put_line('在CASE语句中缺少与' || v_sal || '相关的条件');END;
(3)COLLECTION_IS_NULL
该例外对应于ORA-06531错误。在给集合元素(嵌套表或VARRAY类型)赋值前,必须首先初始化集合元素。如果没有初始化集合元素,则会隐含地触发COLLECTION_IS_NULL例外。
DECLARE  TYPE ename_table_type IS TABLE OF emp.ename%TYPE;  ename_table ename_table_type;BEGIN  SELECT ename INTO ename_table(1) FROM emp WHERE empno = &NO;  dbms_output.put_line('雇员名:' || ename_table(1));  EXCEPTION    WHEN COLLECTION_IS_NULL THEN      dbms_output.put_line('必须使用构造方法初始化集合元素');END;
(4)CURSOR_ALREADY_OPEN
该例外对应于ORA-06511错误。当重新打开已经打开的游标时,会隐含地触发例外CURSOR_ALREADY_OPEN。
DECLARE  CURSOR cur_emp IS  SELECT ename,sal FROM emp;BEGIN  --打开游标  OPEN cur_emp;  FOR emp_record IN cur_emp LOOP    dbms_output.put_line(emp_record.ename);  END LOOP;  EXCEPTION    WHEN CURSOR_ALREADY_OPEN THEN      dbms_output.put_line('游标已经打开');END;
(5)DUP_VAL_ON_INDEX
该例外对应于ORA-00001错误。当在惟一索引所对应的列上键入重复值时,会隐含地触发例外DUP_VAL_ON_INDEX。
BEGIN  UPDATE dept SET deptno = 40 WHERE deptno = &NO;  EXCEPTION    WHEN DUP_VAL_ON_INDEX THEN      dbms_output.put_line('在deptno列上不允许重复值');END;
(6)INVALID_CURSOR
该例外对应于ORA-01001错误。当试图在不合法的游标上执行操作时,会隐含地触发例外INVALID_CURSOR。例如,如果要从未打开的游标提取数据,或者关闭未打开的游标,则会触发该例外。
DECLARE  CURSOR cur_emp IS  SELECT ename,sal FROM emp;  TYPE emp_record_type IS RECORD(    ename emp.ename%TYPE,    sal emp.sal%TYPE  );  emp_record emp_record_type;BEGIN  --未打开游标  FETCH cur_emp INTO emp_record;  --关闭游标  CLOSE cur_emp;  EXCEPTION    WHEN INVALID_CURSOR THEN      dbms_output.put_line('请检查游标是否已经打开');END;
(7)INVALID_NUMBER
该例外对应于ORA-01722错误。当内嵌SQL语句不能有效地将字符转变成数字时,会隐含地触发例外INVALID_NUMBER,例如数字值"100“被写成"1OO"。
BEGIN  UPDATE emp SET sal = sal + '1OO';  EXCEPTION    WHEN INVALID_NUMBER THEN      dbms_output.put_line('输入的数字值不正确');END;
(8)NO_DATA_FOUND
该例外对应于ORA-01403错误。当执行SELECT INTO未返回行,或者引用了索引表未初始化的元素时,会隐含地触发例外NO_DATA_FOUND。
DECLARE  v_sal emp.sal%TYPE;BEGIN  SELECT sal INTO v_sal FROM emp  WHERE LOWER(ename) = LOWER('&ename');  dbms_output.put_line('工资:' || v_sal);  EXCEPTION    WHEN NO_DATA_FOUND THEN      dbms_output.put_line('不存在该雇员');END;
(9)TOO_MANY_ROWS
该例外对应于ORA-01422错误。当执行SELECT INTO语句时,如果返回超过一行,则会触发该例外。
DECLARE  v_ename emp.ename%TYPE;BEGIN  SELECT ename INTO v_ename FROM emp  WHERE sal = 3600;  EXCEPTION    WHEN TOO_MANY_ROWS THEN      dbms_output.put_line('返回多行');END;
(10)ZERO_DIVIDE
该例外对应于ORA-01476错误。当运行PL/SQL块时,如果使用数字值除0,则会隐含地触发该例外。
DECLARE  num1 INT := 100;  num2 INT := 0;  num3 NUMBER(6,2);BEGIN  num3 := num1/num2;  EXCEPTION    WHEN ZERO_DIVIDE THEN      dbms_output.put_line('除数不能为0');END;
(11)SUBSCRIPT_BEYOND_COUNT
该例外对应于ORA-06533错误。当使用嵌套表或VARRAY元素时,如果元素下标超出了嵌套表或VARRAY元素的范围,则会隐含地触发SUBSCRIPT_BEYOND_COUNT例外。
DECLARE  TYPE emp_array_type IS VARRAY(20) OF VARCHAR2(20);  emp_array emp_array_type := emp_array_type('','');BEGIN  dbms_output.put_line(emp_array(3));  EXCEPTION    WHEN SUBSCRIPT_BEYOND_COUNT THEN      dbms_output.put_line('超出下标范围');END;
(12)SUBSCRIPT_OUTSIDE_LIMIT
该例外对应于ORA-06532错误。当使用嵌套表或VARRAY元素时,如果元素下标为负值,则会隐含地触发SUBSCRIPT_BEYOND_COUNT例外。
DECLARE  TYPE emp_array_type IS VARRAY(20) OF VARCHAR2(20);  emp_array emp_array_type := emp_array_type('','');BEGIN  dbms_output.put_line(emp_array(-1));  EXCEPTION    WHEN SUBSCRIPT_OUTSIDE_LIMIT THEN      dbms_output.put_line('嵌套表或VARRAY下标不能为负');END;
(13)VALUE_ERROR
该例外对应于ORA-06502错误。当在PL/SQL块中执行赋值操作时,如果变量长度不足以容纳实际数据,则会隐含地触发例外VALUE_ERROR。
DECLARE  v_ename VARCHAR2(2);BEGIN  SELECT ename INTO v_ename FROM emp WHERE empno = &NO;  dbms_output.put_line(v_ename);  EXCEPTION    WHEN VALUE_ERROR THEN      dbms_output.put_line('变量尺寸不足');END;

2、其他预定义例外

除了在PL/SQL块中经常需要处理常见的预定义例外之外,某些情况下你可能还需要使用其他预定义例外。下面简单介绍这些例外的作用。
(1)LOGIN_DENIED
该例外对应于ORA-01017错误。当PL/SQL应用程序需要连接到Oracle数据库时,如果提供了不正确的用户名或口令,则会隐含地触发例外LOGIN_DENIED。
(2)NOT_LOGGED_ON
该例外对应于ORA-01012错误。如果应用程序没有连接到Oracle数据库,那么在执行PL/SQL块中访问数据库时会隐含地触发例外NOT_LOGGED_ON。
(3)PROGRAM_ERROR
该例外对应于ORA-06501错误。如果出现该错误,则表示存在PL/SQL内部问题,用户此时可能需要重新安装数据字典和PL/SQL系统包。
(4)ROWTYPE MISMATCH
该例外对应于ORA-06504错误。当执行赋值操作时,如果宿主游标变量和PL/SQL游标变量的返回类型不兼容,那么会隐含地触发例外ROWTYPE_MISMATCH。
(5)SELF_IS_NULL
该例外对应于ORA-30625错误。当使用对象类型时,如果在null实例上调用成员方法,则会隐含地触发例外SELF_IS_NULL。
(6)STORAGE_ERROR
该例外对应于ORA-06500错误。PL/SQL块运行时,如果超出内存空间或者内存被损坏,则会隐含地触发例外STORAGE_ERROR。
(7)SYS_INVALID_ROWID
该例外对应于ORA-01410错误。当将字符串转变为ROWID时,必须使用有效的字符串。如果使用了无效的字符串,会隐含地触发例外SYS_INVALID_ROWID。
(8)TIMEOUT_ON_RESOURCE
该例外对应于ORA-00051错误。当如果Oracle在等待资源时出现超时错误,则会隐含地触发例外TIMEOUT_ON_RESOURCE。
  相关解决方案