/*
*处理例外
*/
--例外简介
--处理例外-传递例外
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 too_many_rows then
dbms_output.put_line('查询只能返回单行');
end;
select * from emp;
--捕捉并处理例外
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;
--处理预定义例外
--常用预定义例外
--ACCESS_INTO_NULL
declare
empt emp_type;
begin
empt.name:='SCOTT';
exception
when ACCESS_INTO_NULL THEN
dbms_output.put_line('首先初始化对象emp');
end;
--CASE_NOT_FOUND
DECLARE
v_sal emp.sal%TYPE;
BEGIN
SELECT sal into v_sal from emp where empno=&no;
case
when v_sal<100 then
update emp set sal=sal+100 where empno=&no;
when v_sal<200 then
update emp set sal=sal+150 where empno=&no;
when v_sal<300 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;
select * from emp;
--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(2) from emp
where empno=&no;
dbms_output.put_line('雇员名:'||ename_table(2));
EXCEPTION
WHEN COLLECTION_IS_NULL then
dbms_output.put_line('必须使用构造方法初始化集合元素');
END;
--CURSOR_ALREADY_0PEN
declare
CURSOR emp_cursor is select ename,sal from emp;
begin
open emp_cursor;
for emp_record in emp_cursor loop
dbms_output.put_line(emp_record.ename);
end loop;
exception
when cursor_already_open then
dbms_output.put_line('游标已经打开');
end;
--给dept表加主键
alter table dept add primary key(deptno);
select * from dept;
--DUP_VAL_ON_INDEX
BEGIN
UPDATE dept set deptno=&new_no where deptno=&old_no;
EXCEPTION
when DUP_VAL_ON_INDEX THEN
dbms_output.put_line('在deptno列上不能出现重复值');
END;
--INVALID_CURSOR
DECLARE
cursor emp_cursor is select ename,sal from emp;
emp_record emp_cursor%ROWTYPE;
BEGIN
--open emp_cursor;
FETCH emp_cursor into emp_record;
close emp_cursor;
EXCEPTION
WHEN invalid_cursor then
dbms_output.put_line('请检查游标是否已经打开');
END;
--INVALID_NUMBER
begin
update emp set sal=sal+'1oo';
exception
when invalid_number then
dbms_output.put_line('输入的数字值不正确');
end;
--NO_DATA_FOUND
DECLARE
v_sal emp.sal%TYPE;
BEGIN
select sal into v_sal from emp
where lower(ename)=lower('&name');
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('不存在该雇员');
END;
select * from emp;
--TOO_MANY_ROWS
DECLARE
v_ename emp.ename%TYPE;
BEGIN
select ename into v_ename from emp where sal=&sal;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.put_line('返回多行');
END;
--ZERO_DIVIDE
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;
--SUBSCRIPT_BEYOND_COUNT
declare
type emp_array_type is varray(20) of varchar2(10);
emp_array emp_array_type;
begin
emp_array:=emp_array_type('SCOTT','MARY');
dbms_output.put_line(emp_array(3));
exception
when subscript_beyond_count then
dbms_output.put_line('超出下标范围');
end;
--SUBSCRIPT_OUTSIDE_LIMIT
DECLARE
TYPE emp_array_type is varray(20) of varchar2(10);
emp_array emp_array_type;
BEGIN
emp_array:=emp_array_type('SCOTT','MARY');
dbms_output.put_line(emp_array(-1));
EXCEPTION
WHEN SUBSCRIPT_OUTSIDE_LIMIT THEN
dbms_output.put_line('嵌套表和VARRAY下标不能为负');
END;
--VALUE_ERROR
DECLARE
v_ename varchar2(5);
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;
--处理非预定义例外
--建立主外键约束关系
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept FOREIGN KEY (deptno) REFERENCES dept(deptno);
--因为在DEPT表和EMP表之间具有主外键关系,所以当修改雇员的部门号时,部门号必须在DEPT表中存在。
--如果该部门号在表中不存在,则会隐含触发ORA-02291对应的例外e_integrity,并显示合理的输出信息。
declare
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT(e_integrity,-2291);
begin
update emp set deptno=&dno where empno=&eno;
exception
when e_integrity then
dbms_output.put_line('该部门不存在');
end;
--处理自定义例外
declare
e_integrity EXCEPTION;
PRAGMA EXCEPTION_INIT(e_integrity,-2291);
e_no_employee EXCEPTION;
begin
update emp set deptno=&dno where empno=&eno;
IF SQL%NOTFOUND THEN
RAISE e_no_employee;
END IF;
exception
when e_integrity then
dbms_output.put_line('该部门不存在');
when e_no_employee then
dbms_output.put_line('该雇员不存在');
end;
--使用例外函数
--SQLCODE和SQLERRM
DECLARE
v_ename emp.ename%TYPE;
BEGIN
SELECT ename into v_ename from emp
where sal=&v_sal;
dbms_output.put_line('雇员名:'||v_ename);
EXCEPTION
when no_data_found then
dbms_output.put_line('不存在工资为'||&v_sal||'的雇员');
when others then
dbms_output.put_line('错误号:'||SQLCODE);
dbms_output.put_line(SQLERRM);
END;
select * from emp;
--RAISE_APPLICATION_ERROR
CREATE OR REPLACE PROCEDURE raise_comm
(eno NUMBER,commission NUMBER)
IS
v_comm emp.comm%TYPE;
BEGIN
select comm into v_comm from emp where empno=eno;
if v_comm is null then
raise_application_error(-20001,'该雇员无补助');
end if;
EXCEPTION
when NO_DATA_FOUND THEN
dbms_output.put_line('该雇员不存在');
END;
begin
raise_comm(8,100);
end;
select * from emp for update;
--PL/SQL编译警告
--PL/SQL警告分类
--分成三类警告消息,PL/SQL警告分类如下
--SEVERE:该种警告用于检查可能出现的不可预料结果或错误结果,例如参数的别名问题
--PERFORMANCE:该类警告用于检查可能引起的性能问题,例如在执行INSERT操作时为NUMBER列提供了VARCHAR2类型的数据
--INFORMATIONAL:该类警告用于检查子程序中的死代码
--ALL:该关键字用于检查所有警告(SEVERE,PERFORMACE,INFORMATIONAL)
--检测死代码
CREATE OR REPLACE PROCEDURE dead_code AS
x number:=10;
BEGIN
if x=10 then
x:=20;
else
x:=100; --死代码(永远不会执行)
end if;
END dead_code;
--SQL*PLUS上执行如下命令行
alter session set PLSQL_WARNINGS='ENABLE:INFORMATIONAL';
alter procedure dead_code compile;
show errors;
--检测引起性能问题的代码
CREATE OR REPLACE PROCEDURE update_sal
(name varchar2,salary varchar2)
is
begin
update emp set sal=salary where ename=name;
end;
--SQL*PLUS上执行如下命令行
ALTER SESSION SET PLSQL_WARNINGS='ENABLE:PERFORMANCE';
ALTER PROCEDURE update_sal compile;
show errors;