PL/SQL中的几种异常处理方法

异常处理

这是Pona的文章,我斗胆将其贴上来,Pona不要介意哦!^_^

 

PL/SQL里,有三种方法可以在处理大批量数据时不会因为一条或几条数据错误而导致异常中止程序。

 

1、用Fetch into a cursor%TYPE把要处理的数据放到记录集里。当一条数据不符条件时,用标签<<NEXT_RECORD>>和GOTO NEXT_RECORD跳转语句使程序忽略这一条,转到下一条继续处理。

-------------------------------------------------------------------------------

-- Function Name     :  CalculateImportCharge

-- Function Desc     :  Calculate Import Charge

-- Created by        :  Author

-- Created Date      :  2003-05-16

-------------------------------------------------------------------------------

    FUNCTION CalculateImportCharge (

        p_i_job_id        IN VARCHAR2,

        p_i_as_of_date_id IN VARCHAR2) RETURN NUMBER

    AS

        CURSOR cur_ShipBlHeader IS

            SELECT import_folder_no

            FROM GMY_SHIP_BL_HEADER

            WHERE CANCEL_FLG = GMY_GA000_PKG.BL_CANCEL_FLG_OFF;

        rec_ShipBlHeader        cur_ShipBlHeader%ROWTYPE;

    BEGIN

        OPEN cur_ShipBlHeader;

        FETCH cur_ShipBlHeader INTO rec_ShipBlHeader;

        WHILE cur_ShipBlHeader%FOUND LOOP

            x_num_error_code := GMY_GA000_PKG.CheckValidMasterBlNo (

                p_i_job_id,

                p_i_as_of_date_id,

                rec_ShipBlHeader.import_folder_no,

                x_vch_message);

            IF x_num_error_code

                IN (GMY_GA000_PKG.gn#NG, GMY_GA000_PKG.INVALID_BL_NO) THEN

                x_vch_message :=

                        p_i_job_id

                       || ' WARNING: Function CheckValidMasterBlNo @'

                       || ' Import folder '

                       || rec_ShipBlHeader.import_folder_no

                       || ' - Invalid BL No.';

                COM_LOG.PUTLINE (p_i_job_id, x_vch_message);

                GOTO NEXT_RECORD;

            END IF;

            x_num_error_code := CheckExistsOfAccDate (

                p_i_job_id,

                p_i_as_of_date_id,

                rec_ShipBlHeader.import_folder_no);

            IF x_num_error_code = GMY_GA000_PKG.gn#NG THEN

                GOTO NEXT_RECORD;

            END IF;

            COMMIT;

            <<NEXT_RECORD>>

            FETCH cur_ShipBlHeader INTO rec_ShipBlHeader;

        END LOOP;

        CLOSE cur_ShipBlHeader;

        RETURN GMY_GA000_PKG.gn#OK;

    EXCEPTION

        WHEN OTHERS THEN

            x_vch_message :=

                    p_i_job_id

                 || ' ERROR:   Function CalculateImportCharge @ '

                 || SUBSTR (SQLERRM (SQLCODE), 1, 100);

            COM_LOG.PUTLINE (p_i_job_id, x_vch_message);

            RETURN GMY_GA000_PKG.gn#NG;

END CalculateImportCharge;

2、当使用the Cursor FOR Loop循环时,在Loop循环里,把会出问题的情况写进一个独立的block块中,这个块包括完整的begin、end部分及exception异常处理部分。这样即使一条数据出现异常,也会继续执行下一条。

-------------------------------------------------------------------------------

-- Function Name     : GenerateInsCostInfRec

-- Function Desc     : Generate records to transmit in INF table

-- Created by        : SISS(AP)

-- Created Date      : 2003-03-26

-- ----------------------------------------------------------------------------

    FUNCTION GenerateInsCostInfRec (

        p_i_job_id             IN       VARCHAR2,

        p_i_as_of_date_id      IN       VARCHAR2) RETURN NUMBER

    AS

        CURSOR cur_cost IS

            SELECT cost.ROWID costRowId,

                   cost.import_folder_no,,

                   cost.insur_trans_id

            FROM GMY_COST_BL cost,

                 GMY_COMMON_MST mst

            WHERE cost.import_folder_no=invheader.import_folder_no

            AND cost.billing_amt_num IS NOT NULL

            AND cost.billing_amt_num!=0

            AND cost.insur_db_cr!=0;

    BEGIN

        FOR rec_cost IN cur_cost LOOP

            BEGIN

                x_num_ret_value := GMY_GA000_PKG.CheckValidMasterBlNo(

                                p_i_job_id,

                                p_i_as_of_date_id,

                                rec_cost.import_folder_no,

                                x_vch_error_msg);

                IF x_num_ret_value = GMY_GA000_PKG.VALID_BL_NO THEN

                    INSERT INTO GMY_COST_INS_INF(

                        cost_trx_id,,

                        created_by,

                        program_name)

                    VALUES(

                        GMY_COST_INS_INF_S.NEXTVAL,

                        PRG_NAME,

                        PRG_NAME);

                ELSIF x_num_ret_value = GMY_GA000_PKG.INVALID_BL_NO THEN

                    x_vch_error_msg := p_i_job_id

                        || ' Import folder '

                        || rec_cost.import_folder_no

                        || ' has repeated BL No. with other import folder.'

                        || ' Failed in insurance cost transmission.';

                    COM_LOG.PUTLINE(p_i_job_id, x_vch_error_msg);

                END IF;

            EXCEPTION

                WHEN OTHERS THEN

                    IF SQL%ROWCOUNT > 0 THEN  -- check for 'too many rows'

                       x_vch_error_msg := p_i_job_id||' '||

                           SUBSTR(SQLERRM(SQLCODE),1,100);

                       COM_LOG.PUTLINE(p_i_job_id, x_vch_error_msg);

                    ELSE

                       x_vch_error_msg := p_i_job_id||' '||

                           SUBSTR(SQLERRM(SQLCODE),1,100);

                       COM_LOG.PUTLINE(p_i_job_id, x_vch_error_msg);

                END IF;

            END;

        END LOOP;

        COMMIT;

        RETURN GMY_GA000_PKG.gn#OK;

    EXCEPTION

      WHEN OTHERS THEN

          x_vch_error_msg := p_i_job_id||' '||SUBSTR(SQLERRM(SQLCODE),1,100);

          COM_LOG.PUTLINE(p_i_job_id, x_vch_error_msg);

          ROLLBACK;

          RETURN GMY_GA000_PKG.gn#NG;

END GenerateInsCostInfRec;

3、当使用the Cursor FOR Loop循环时,在Loop循环里,把会出问题的情况拆分成子函数,分别处理。

----------------------------------------------------------------------------

-- Function Name      :  CopyDsToActualDs

-- Function Desc      :  Copy the records from DS DB to Actual DS DB.

-- Created by         :  Author

-- Created Date       :  2003-02-20

----------------------------------------------------------------------------

   FUNCTION CopyDsToActualDs (

        p_i_job_id         IN   VARCHAR2,

        p_i_as_of_date_id  IN   VARCHAR2)  RETURN NUMBER

    IS

        CURSOR cur_DsScc IS

            SELECT *

            FROM   GMY_DS_SCC;

    BEGIN

        FOR rec_DsHead IN cur_DsScc LOOP

            x_num_error_code := InsToActualScc(

                        p_i_job_id,

                        p_i_as_of_date_id,

                        rec_DsHead.order_by_code,

                        rec_DsHead.po_code,

                        rec_DsHead.wh);

        END LOOP;

    EXCEPTION

        WHEN OTHERS THEN

            x_vch_error_msg := p_i_job_id

                ||' Function Name: CopyDsToActualDs';

            COM_LOG.PUTLINE(p_i_job_id,x_vch_error_msg);

            x_vch_error_msg:=p_i_job_id||' '||SUBSTR(SQLERRM(SQLCODE),1,100);

            COM_LOG.PUTLINE(p_i_job_id, x_vch_error_msg);

            ROLLBACK;

        RETURN GMY_GA000_PKG.gn#NG;

    END CopyDsToActualDs;

----------------------------------------------------------------------------

-- Function Name      :  InsToActualScc

-- Function Desc      :  Deal with insert section.

-- Created by         :  Author

-- Created Date       :  2003-03-13

----------------------------------------------------------------------------

    FUNCTION InsToActualScc(

        p_i_job_id                      IN       VARCHAR2,

        p_i_as_of_date_id               IN       VARCHAR2,

        p_i_order_by_code               IN       VARCHAR2,

        p_i_po_code                     IN       VARCHAR2,

        p_i_wh                          IN       VARCHAR2

    ) RETURN NUMBER

    IS

        x_vch_error_msg VARCHAR2(255);

    BEGIN

        INSERT INTO GMY_ACTUAL_DS_SCC(

                order_by_code,

                po_code,

                wh )

        VALUES( p_i_order_by_code,

                p_i_po_code,

                p_i_wh);

        COMMIT;

        RETURN GMY_GA000_PKG.gn#OK;

    EXCEPTION

        WHEN OTHERS THEN

            x_vch_error_msg := p_i_job_id||' Function Name: InsToActualScc';

            COM_LOG.PUTLINE(p_i_job_id,x_vch_error_msg);

            x_vch_error_msg := p_i_job_id

                ||' The key of the record that failed to insert is: ';

            COM_LOG.PUTLINE(p_i_job_id,x_vch_error_msg);

            ROLLBACK;

        RETURN GMY_GA000_PKG.gn#NG;

    END InsToActualScc;

时间: 2024-11-16 04:33:52

PL/SQL中的几种异常处理方法的相关文章

oracle-Oracle PL/SQL 外键关联的异常处理

问题描述 Oracle PL/SQL 外键关联的异常处理 删除父表记录后, 若不写异常处理器,则会报错,并自动回滚所有被删除的数据. 若写了异常处理器,则在异常处理中回滚,只能恢复父表记录, 而子表中对应的记录被删除仍无法恢复. 预期结果应该是在回滚之后被删除的所有记录都恢复. 解决方案 外键关联肯定不能直接删除父表啊 可以这么做, 方法一:先删除外键关联,再去删除父表 方法二:先删除子表,再去删除父表 解决方案二: Oracle:pl/sql 异常处理 解决方案三: 同意1楼说的,删子,再删父

PL/SQL中的多进程通信技术简介

进程 PL/SQL是基于Oracle的一个主流应用程序编程语言,它的特点是将SQL语句与过程化程序开发语言相结合,以实现更为复杂的商业逻辑.本文主要就其中多进程通信进行讨论. 显然,多进程技术是用来提高应用的并发性,进而提高整个系统的执行效率,那么如何在PL/SQL中实现多进程的通信呢?其实,PL/SQL其设计的初衷主要是增强SQL语句的功能,而没有考虑到其他编程语言的高级功能,所以在PL/SQL中实现多进程通信只能借助于Oracle提供的两个开发包:DBMS_PIPE和DBMS_ALERT.

借助两个开发包在PL/SQL中实现多进程通信

PL/SQL是基于Oracle的一个主流应用程序编程语言,它的主要特点是将SQL语 句与过程化程序开发语言相结合,以实现更为复杂的商业逻辑.本文主要就其中 多进程通信进行讨论. 显然,多进程技术是用来提高应用的并发性,进而提高整个系统的执行效率, 那么如何在PL/SQL中实现多进程的通信呢?其实,PL/SQL其设计的初衷主要是增 强SQL语句的功能,而没有考虑到其他编程语言的高级功能,所以在PL/SQL中实现 多进程通信只能借助于Oracle提供的两个开发包:DBMS_PIPE和DBMS_ALE

怪异问题!sql在pl/sql中执行结果与java jdbc执行结果不一致

问题描述 做一查询系统(struts2+myeclipse+tomcat+oracle9),一般先在pl/sql中测试sql语句,无问题后在action中使用oracle thin模式连接数据库,执行sql语句,然后将查询结果存入HashMap后输出至jsp页面.出现如下怪异问题:1.在pl/sql中测试sql语句时结果正常.结果中有6个字段,其中两个字段为count()函数统计出的数值.2.将在pl/sql中测试过的sql语句写入struts2的action中,通过jdbc thin模式执行,

pl/sql中的forall简单测试

之前写过一篇bulk collect的博文,只是对于bulk collect做了简单的实例.http://blog.itpub.net/23718752/viewspace-1289696/ 其实不光是bulk collect,forall对于pl/sql的性能的提升也是相当大的. 可以参见下面的两个图,可以看到其实在pl/sql中,可能很多时候我们所写的pl/sql代码会在sql引擎和plsql引擎建进行上下文的切换,这个过程还是很耗费时间的. 而forall却是相反,是提供一次上下文切换,会

SQL中的五种数据类型

数据|数据类型 简要描述一下SQL中的五种数据类型:字符型,文本型,数值型,逻辑型和日期型 字符型 VARCHAR VS CHAR VARCHAR型和CHAR型数据的这个差别是细微的,但是非常重要.他们都是用来储存字符串长度小于255的字符. 假如你向一个长度为四十个字符的VARCHAR型字段中输入数据Bill Gates.当你以后从这个字段中取出此数据时,你取出的数据其长度为十个字符--字符串Bill Gates的长度. 现在假如你把字符串输入一个长度为四十个字符的CHAR型字段中,那么当你取

Oracle中PL/SQL中if语句的写法介绍

以下是对Oracle中PL/SQL中if语句的写法进行了详细的分析介绍,需要的朋友可以过来参考下   复制代码 代码如下: /* If语句: 判断用户输入的数字. */ set serveroutput on --接收键盘输入 accept num prompt '请输入一个数字:'; declare   --将屏幕输入的数字付给变量   pnum number := # begin   if pnum = 0 then dbms_output.put_line('您输入的是0');   end

sql中获得部分时间的方法

  sql中获得部分时间的方法: 有的时候,我们可能希望按月.按天.按年做一些数据统计,但是,我们实际保存的数据可能是一个很精确的发生时间,可能是到秒.如何根据一个时间之截取其中的一部分就成了问题. 有两个解决方法: 最直接的想法利用DatePart或者Year.Month.Day函数 CAST( ( STR( YEAR( GETDATE() ) ) + '/' + STR( MONTH( GETDATE() ) ) + '/' + STR( DAY( GETDATE() ) ) ) AS DA

pl/sql中操作DML语句

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 INSERT     DECLARE  v_empno emp.empno%TYPE := &empno;  v_ename emp.ename%TYPE := '&ename';  v_salary emp.sal%TYPE := &sal;  BEGIN  INSERT INTO emp(empno,ename,s