oracle 10g: PL/SQL User's Guide and Reference

 ---> 10 Handling PL/SQL Errors

 ---> Summary of Predefined PL/SQL Exceptions 

系统预定义异常(有名字的错误代码):

TOO_MANY_ROWS : SELECT INTO返回多行

INVALID_CURSOR :非法指针操作(关闭已经关闭的游标)

ZERO_DIVIDE :除数等于零

DUP_VAL_ON_INDEX :违反唯一性约束

ACCESS_INTO_NULL: 未定义对象 

CASE_NOT_FOUND: CASE 中若未包含相应的 WHEN ,并且没有设置 ELSE 时 

COLLECTION_IS_NULL: 集合元素未初始化 

CURSER_ALREADY_OPEN: 游标已经打开 

DUP_VAL_ON_INDEX: 唯一索引对应的列上有重复的值 

INVALID_NUMBER: 内嵌的 SQL 语句不能将字符转换为数字 

NO_DATA_FOUND: 使用 select into 未返回行,或应用索引表未初始化的元素时 

SUBSCRIPT_BEYOND_COUNT:元素下标超过嵌套表或 VARRAY 的最大值 

SUBSCRIPT_OUTSIDE_LIMIT: 使用嵌套表或 VARRAY 时,将下标指定为负数  

VALUE_ERROR: 赋值时,变量长度不足以容纳实际数据 

LOGIN_DENIED: PL/SQL 应用程序连接到 oracle 数据库时,提供了不正确的用户名或密码 

NOT_LOGGED_ON: PL/SQL 应用程序在没有连接 oralce 数据库的情况下访问数据 

PROGRAM_ERROR: PL/SQL 内部问题,可能需要重装数据字典& pl./SQL 系统包 

ROWTYPE_MISMATCH: 宿主游标变量与 PL/SQL 游标变量的返回类型不兼容 

SELF_IS_NULL: 使用对象类型时,在 null 对象上调用对象方法 

STORAGE_ERROR: 运行 PL/SQL 时,超出内存空间 

SYS_INVALID_ID: 无效的 ROWID 字符串 

TIMEOUT_ON_RESOURCE: Oracle 在等待资源时超时 

oracl 11g: Pl/SQL LANGUAGE REFERENCE

 ----> 11  PL/SQL error handling

 ----> Predefined Exceptions

练习 1:捕获预定义异常

declare

  v1 emp.sal%type;

begin

  select sal into v1 from emp;

end;

/

declare

  v1 emp.sal%type;

begin

  select sal into v1 from emp;

exception

  when TOO_MANY_ROWS then

   dbms_output.put_line(sqlcode||';'||sqlerrm);

end;

/

declare

   v_ename employees.last_name%type;

begin

   select last_name into v_ename from employees;

exception

   when too_many_rows then

        dbms_output.put_line('too many rows,you should add a condition');

end;

/



练习 2:捕获预定义异常

declare

  v1 emp.sal%type;

begin

  select sal into v1 from emp where empno=7777;

exception

  when TOO_MANY_ROWS then

    dbms_output.put_line('more person !');

--  when NO_DATA_FOUND then

--    dbms_output.put_line('no rows selected!');

  when others then --other执行器

    dbms_output.put_line(sqlcode||';'||sqlerrm);

end;

/

declare

   v_sal hr.employees.salary%type;

begin

   select salary into v_sal from hr.employees where department_id= &ID;

   dbms_output.put_line(v_sal);

exception

   WHEN TOO_MANY_ROWS then

        dbms_output.put_line('there are too many rows to return.');

   when NO_DATA_FOUND THEN

        DBMS_OUTPUT.PUT_LINE('there is no data to return.');

end;

declare

   v_ename employees.last_name%type;

begin

   select last_name into v_ename from employees;

exception

   when too_many_rows then

        dbms_output.put_line('sqlcode :'||sqlcode ||chr(10)||'sqlerrm :'||sqlerrm);

end;

/

sqlcode :-1422

sqlerrm :ORA-01422: exact fetch returns more than requested number of rows

练习 3:捕获错误代码和错误描述,借助预定义函数sqlcode(ERROR代码),sqlerrm(ERROR文本)

begin

  update emp set deptno=60;

  dbms_output.put_line('ok');

exception

  when TOO_MANY_ROWS then

    dbms_output.put_line('more person !');

  when NO_DATA_FOUND then

    dbms_output.put_line('no person !');

  when others then --other执行器

    dbms_output.put_line(sqlcode||';'||sqlerrm);

end;

/

练习 4:捕获非预定义异常(捕获oracle错误代码)

declare

  fk_error  exception;--声明异常

  pragma exception_init(fk_error,-2292);--使用编译指示器将异常名称和oracle的错误代码绑定

begin

  delete dept; --oracle自动传播错误(fk_error)

  dbms_output.put_line('ok');

exception

  when TOO_MANY_ROWS then

    dbms_output.put_line('more person ');

  when NO_DATA_FOUND then

    dbms_output.put_line('no person ');

  when fk_error then

    dbms_output.put_line('infringe forign key !');  

end;

/

declare

   pk_fk_error exception;

   pragma exception_init(pk_fk_error,-2292);

begin

   delete hr.departments;

   dbms_output.put_line('It had been deleted.');

exception

   when pk_fk_error then

        dbms_output.put_line('It can not delete.');

end;

/

It can not delete.

用户自定义异常的sqlcode代码段:-20001 ~ -20999

练习 5:捕获用户自定义的异常:

declare

  my_error EXCEPTION;

  PRAGMA EXCEPTION_INIT(my_error, -20001);--编译指示,将命名的异常与ORACLE ERROR关联

BEGIN

  raise_application_error(-20001,'工资不能被改动!');--将异常传送到环境

  UPDATE e SET SAL=1000;

EXCEPTION

  WHEN NO_DATA_FOUND THEN

    DBMS_OUTPUT.PUT_LINE('未检索到数据!');

  WHEN TOO_MANY_ROWS THEN

    DBMS_OUTPUT.PUT_LINE('SELECT返回多行数据!');

  WHEN MY_ERROR THEN

    DBMS_OUTPUT.PUT_LINE('E表工资不可以被修改!');

end;

/

declare

   my_excep EXCEPTION;

   PRAGMA EXCEPTION_init(my_excep,-20001);

   v_did hr.employees.department_id%type := &id;

begin

   if v_did != 10 then

        raise_application_error(-20001,'my own exception.');

   else

       update hr.employees set salary=salary+1 where department_id=v_did;

       dbms_output.put_line('ok');

   end if;

end;



练习 6:捕获用户自定义的异常

declare

  my_error EXCEPTION;

  PRAGMA EXCEPTION_INIT(my_error, -20001);

  v_empno number(4):=&p_empno;

begin

  IF TO_CHAR (SYSDATE, 'HH24') NOT BETWEEN '08' AND '14' OR TO_CHAR (SYSDATE, 'DY') IN ('星期六', '星期日') THEN

    RAISE my_error;

  else

    insert into e(empno) values (v_empno);

    dbms_output.put_line('insert 成功!');

  END IF;

exception

  when my_error then

    dbms_output.put_line('该时间段不能向E表插入数据!');

end;

/

declare

   v_raise_sal number := &raise_sal;

   my_error EXCEPTION;

   PRAGMA exception_init(my_error,-20001);

begin

   if v_raise_sal > 1000 then

      raise_application_error(-20001,'can not raise so much money.');

   else

      update employees set salary=salary+v_raise_sal;

   end if;

--exception

--   when my_error then

--       dbms_output.put_line('you can not raise.');

end;

/

错误报告:

ORA-20001: can not raise so much money.

ORA-06512: at line 7

****************************************************************************************************

练习 7:打印 ORA-##### 错误编号和描述:

SPOOL D:ORACLE_ERROR.TXT

SET SERVEROUTPUT ON

DECLARE

  ERR_MSG VARCHAR2(4000);

  ERR_CODE NUMBER(10);

BEGIN

  DBMS_OUTPUT.ENABLE(1000000);

  FOR ERR_NUM IN 20000..20999

  LOOP

    ERR_CODE:=sqlcode;

    ERR_MSG := SQLERRM(-ERR_NUM);

     IF ERR_MSG NOT LIKE '%Message '||ERR_NUM||' not found%' then

       dbms_output.put_line(ERR_MSG);

     END IF;

  END LOOP;

END;

/

SPOOL OFF;

--嵌套的PL/SQL代码段的异常处理

declare

  v_ename varchar2(10);

begin

  select ename into v_ename from emp where empno=7839;

  dbms_output.put_line(v_ename);

    declare

      v1 emp.sal%type;

    begin

      select sal into v1 from emp;

    exception

      when TOO_MANY_ROWS then

       dbms_output.put_line(sqlcode||';'||sqlerrm);

    end;

  dbms_output.put_line('ok');

end;

/

--内部pl/sql代码段,进行了异常处理,是所有外部程序可以正常执行;

declare

   v_name employees.last_name%type;

begin

   select last_name into v_name from hr.employees

   where employee_id=100;

   declare

       v_no departments.department_id%type;

   begin

       select department_id into v_no from departments;

   exception

      when  OTHERS then

          dbms_output.put_line('too may rows');

   end;

   dbms_output.put_line(v_name);

end;

/

too may rows

King

--内部pl/sql代码段异常

declare

   v_name hr.employees.last_name%type;

begin

   select last_name into v_name from hr.employees where employee_id=100;

   dbms_output.put_line(v_name);

   declare

       v_sal hr.employees.salary%type;

   begin

       select salary into v_sal from employees;

       dbms_output.put_line('inner pl/sql block');

--   exception

--       when too_many_rows then

--           dbms_output.put_line('inner exception capured.');

   end;

   dbms_output.put_line('outer block');

exception

   when too_many_rows then

       dbms_output.put_line('outer exception captured.');

end;