• Oracle_PL/SQL(9) 例外处理


    例外处理
    1.例外分类:预定义例外,非预定义例外,自定义例外三种
    传递例外:如果在例外处理部分exception没有捕捉例外,oracle会将例外传递到调用环境.
    捕捉并处理例外:使用例外处理部分完成
    exception
    when exception1 then
    statement1;
    when exception2 then
    statement2;
    ...
    when others then --必须是例外处理部分的最后一条子句
    statement_n;
    ...

    2.预定义例外
    2.1系统预定义例外有21个,如下:
    dup_val_on_index:ora-00001错误。
    当在唯一索引所对应的列上键入重复值时,触发例外
    zero_divide:ora-01476错误。
    如果使用数字值除0,则会隐含触发例外
    invalid_number:ora-01722错误。
    当sql语句不能有效的将字符转变成数字时,会隐含触发例外
    no_date_found:ora-01403错误。
    当执行select into 未返回行,或者引用了索引表未初始化的元素时,会隐含触发例外
    too_many_rows:ora-01422错误。
    当执行select into 语句时,如果返回超过一行,则会触发例外
    access_into_null:ora-06530错误。
    在引用对象属性之前,必须首先初始化对象,否则触发例外
    value_error:ora-06502错误。
    如果变量长度不足以容纳实际数据,则会隐含的出发例外
    case_not_found:ora-06592错误。
    在编写case语句时,如果在when子句中没有包含必须的条件分支(else),
    并且没有包含else子句,就会触发
    cursor_already_open:ora-06511错误。
    当重新打开已经打开的游标时,会隐含的触发例外.
    已经使用open打开了显示游标,并执行for循环,就会隐含的触发该例外
    invalid_cursor:ora-01001错误。
    当试图在不合法的游标上执行操作时,会隐含的触发例外.
    要从未打开的游标提取数据,或者关闭未打开的游标,则触发例外
    rowtype_mismatch:ora-06504错误。
    宿主游标变量和pl/sql游标变量的返回类型不兼容
    collection_is_null:ora-06531错误。
    在给集合元素(嵌套表和varray类型)赋值前,必须首先初始化集合元素,否则触发例外
    subscript_beyond_count:ora-06533错误。
    当使用嵌套表或varray元素时,如果元素下标超出了嵌套表或varray元素的范围,
    则回隐含的触发例外
    subscript_outside_limit:ora-06532错误。
    当使用嵌套表或varray元素时,如果元素下标为负值,则会隐含触发例外
    login_denied:ora-01017错误。
    连接数据库时,提供了不正确的用户名和口令
    not_logged_on:ora-01012错误。
    没有连接到数据库
    program_error:ora-06501错误。
    存在pl/sql内部问题,可能需要重新安装数据字典和pl/sql系统包
    self_is_null:ora-30625错误。
    使用对象类型时,如果在null实例上调用成员方法,则会隐含触发例外
    storage_error:ora-06500错误。
    如果超出内存或者内存被损坏
    sys_invalid_rowid:ora-01410错误。
    当字符串转变为rowid时,必须使用有效的字符串,否则触发例外
    timeout_on_resource:ora-00051错误。
    oracle在等待资源时出现超时错误


    2.2 举例
    例1: case_not_found:
    ora-06592.在编写CASE语句时,如果在WHEN子句中没有包含必须的条件分支(else),
    并且没有包含ELSE子句,就会触发
    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;

    例2: collection_is_null:
    ora-06531 在给集合元素(嵌套表和VARRAY类型)赋值前,
    必须首先初始化集合元素,否则触发例外
    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('必须使用构造方法初始化集合元素');
    when subscript_beyond_count then
    dbms_output.put_line('下标超出了集合元素的范围');
    end;

    3.处理非预定义例外
    使用非预定义例外包括三步:
    在定义部分定义例外名,
    然后在例外和ORACLE错误之间建立关联,
    最终在例外处理部分捕捉并处理例外.
    当定义oracle错误和例外之间的关联关系时,需要使用伪过程exception_init
    update emp set deptno=99 where empno=7788;
    ORA-02291

    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;

    4.处理自定义例外
    自定义例外与oracle错误没有任何关联。
    与预定义和非预定义不同,自定义例外必须显示触发。
    declare
    e_no_employee exception;
    begin
    update emp set deptno=20 where empno=&eno;
    if sql%notfound then
    raise e_no_employee;
    end if;
    exception
    when e_no_employee then
    dbms_output.put_line('该雇员不存在');
    end;

    5.使用例外函数
    函数sqlcode用于取得oracle错误号,而sqlerrm则用于取得与之相关的错误信息。
    在存储过程、函数、包中可以使用raise_application_error自定义错误号和错误消息。
    5.1 sqlcode和sqlerrm
    declare
    v_ename emp.ename%type;
    -- v_code varchar2(100);
    -- v_errm varchar2(100);
    begin
    select ename into v_ename from emp where empno=&empno;
    --exception
    -- when others then
    -- dbms_output.put_line('错误号:'||sqlcode);
    -- dbms_output.put_line('错误信息:'||sqlerrm);
    -- v_code:=sqlcode;
    -- v_errm:=sqlerrm;
    -- insert into error_log (id,code,errm,e_date)
    -- values (seq_log.nextval,v_code,v_errm,sysdate);
    end;

    5.2 raise_application_error
    用于在PL/SQL应用程序中自定义错误消息。
    raise_application_error只能在过程,函数,包,触发器中使用,不能在匿名块中使用。
    语法:raise_application_error(error_number,message);
    说明:
    error_number:必须在-20000和-20999之间的负整数.
    message:最大2048字节
    举例:
    create or replace procedure proc_trans_value(p_acid_out number,p_acid_in number,p_value number)
    is
    l_cnt number(8):=0;
    l_value account.value%type;
    begin
    select count(1) into l_cnt from account where accountid=p_acid_out;
    if l_cnt=1 then
    select value into l_value from account where accountid=p_acid_out;
    if l_value>=p_value then
    update account set value=value-p_value where accountid=p_acid_out;
    else
    raise_application_error(-20003,'[转出账户金额不足]');
    end if;
    else
    raise_application_error(-20001,'[转出账户不存在]');
    end if;
    select count(1) into l_cnt from account where accountid=p_acid_in;
    if l_cnt=1 then
    update account set value=value+p_value where accountid=p_acid_in;
    else
    raise_application_error(-20002,'[转入账户不存在]');
    end if;
    end proc_trans_value;

    insert into account values (111,'a',10000);
    insert into account values (112,'b',100);
    exec proc_trans_value(111,112,20000)

  • 相关阅读:
    C# TCP异步服务/客户端
    Entity Framework Batch Update and Future Queries
    用c#编写socks代理服务器,大白话细述协议的最重要部分。
    ArraySegment AsEnumerable
    c#数据包拦截+网络编程
    为.Net Remoting增加基于SKYPE API的P2P传输通道
    如何看PDA的IP
    基本搞定PDA HTTP Server
    PDA SOAP Server探索历程(1)
    疑难问题之PDA SOAP Server
  • 原文地址:https://www.cnblogs.com/BradMiller/p/9279715.html
Copyright © 2020-2023  润新知