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;