精通Oracle10编程SQL(10)处理例外

/*
 *处理例外
 */
--例外简介
--处理例外-传递例外
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;

猜你喜欢

转载自bijian1013.iteye.com/blog/2222461