db2 存储过程 异常处理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了db2 存储过程 异常处理相关的知识,希望对你有一定的参考价值。

存储过程如下:

CREATE PROCEDURE ...
LANGUAGE SQL
...
BEGIN
--load 数据块儿1

--load 数据块儿2

END;
现在程序运行之后,load数据块儿1在导入数据的时候,因为文件中的数据可能格式有些不正确(比如非空字段处的值是空等)导致某些数据无法导入,这个时候,该存储过程就会退出了,如何在这里控制,若是load失败就进行某些操作,或者抛出异常

DB2新手,望高手可怜,给予解答,谢谢啦

存储过程异常的处理:
DECLARE handler-type HANDLER FOR condition handler-action
  
异常处理器类型(handler-type)有以下几种:
  CONTINUE 在处理器操作完成之后,会继续执行产生这个异常语句之后的下一条语句。
  EXIT 在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。
  UNDO 在处理器操作执行之前,DB2会回滚存储过程中执行的SQL操作。在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。
  异常处理器可以处理基于特定SQLSTATE值的定制异常,或者处理预定义异常的类。预定义的3种异常如下所示:
  NOT FOUND 标识导致SQLCODE值为+100或者SQLSATE值为02000的异常。这个异常通常在SELECT没有返回行的时候出现。
  SQLEXCEPTIOIN 标识导致SQLCODE值为负的异常。
  SQLWARNING 标识导致警告异常或者导致+100以外的SQLCODE正值的异常。
  如果产生了NOT FOUND 或者SQLWARNING异常,并且没有为这个异常定义异常处理器,那么就会忽略这个异常,并且将控制流转向下一个语句。如果产生了SQLEXCEPTION异常,并且没有为这个异常定义异常处理器,那么存储过程就会失败,并且会将控制流返回调用者。
  以下示例声明了两个异常处理器。 EXIT处理器会在出现SQLEXCEPTION 或者SQLWARNING异常的时候被调用。EXIT处理器会在终止SQL程序之前,将名为stmt的变量设为"ABORTED",并且将控制流返回给调用者。UNDO处理器会将控制流返回给调用者之前,回滚存储过程体中已经完成的SQL操作。
 
 清单3:异常处理器示例
  DECLARE EXIT HANDLER FOR SQLEXCEPTION, SQLWARNING SET stmt = 'ABORTED';
  DECLARE UNDO HANDLER FOR NOT FOUND;
  如果预定义异常集不能满足需求,就可以为特定的SQLSTATE值声明定制异常,然后再为这个定制异常声明处理器。语法如下:
  
清单4:定制异常处理器
  DECLARE unique-name CONDITION FOR SQLSATE 'sqlstate'
  处理器可以由单独的存储过程语句定义,也可以使用由BEGIN…END块界定的复合语句定义。注意在执行符合语句的时候,SQLSATE和SQLCODE的值会被改变,如果需要保留异常前的SQLSATE和SQLCODE,就需要在执行复合语句的第一个语句把SQLSATE和SQLCODE赋予本地变量或参数。
  通常,会为存储过程定义一个执行状态的输出参数(例如:poGenStatus)。
declare sqlcode integer default 0;
begin
declare continue handler for sqlexception set ret = sqlcode;
declare continue handler for sqlwarning set ret = sqlcode;
declare continue handler for not found set ret = sqlcode;
end ; --异常的声明

--异常的处理
if sqlcode< 0 or sqlcode= 100 then
set O_RetCod = RetCode;
set O_RetMsg = 'CLN02:产品实例关联客户过程出错!';
insert into LOG.OPER_LOG_TAB(PROC_NAME,OBJ_TAB,REGION_COD,OPER_COUNT,ERR_CODE,DATA_TIME,OPER_TIME)
values('P_DW_CLEAN','GLOBAL TEMP',0,0,retcode,CHAR(last_3_mon_time),current TIMESTAMP);
return;
else
set RetCode = 0;
end if;
参考技术A TRUNCATE TABLE output_debug IMMEDIATE@
BEGIN
  -- 错误标志
  DECLARE error_flag INT;
  
 -- DB2 中,如果需要使用 sqlcode ,那么必须先 DECLARE 以后,才能使用。
  DECLARE sqlcode  INT;

  -- 定义错误处理
  -- 如果发生错误,继续处理
  -- 但是把标志位设置为 sqlcode
  DECLARE CONTINUE HANDLER
  FOR
  SQLEXCEPTION SET error_flag=sqlcode;

  -- 错误标志,首先设置为正常.
  SET error_flag = 0;

  -- 先更新.
  UPDATE test_main SET value = 'Test1' WHERE id = 1;

  -- 插入一行主键重复数据.
  INSERT INTO test_main VALUES(1, 'PK');
  INSERT INTO output_debug VALUES('执行结果:'|| TO_CHAR(error_flag));
END
@



db2 => select * from test_main WHERE id = 1@
ID          VALUE
----------- ----------
          1 Test1
  1 条记录已选择。


db2 => select * from output_debug@
DATA
-----------------------------------
执行结果:-803
  1 条记录已选择。

本回答被提问者采纳
参考技术B 创建SQL存储过程(CREATE PROCEDURE (SQL) statement )
CREATE PROCEDURE procedure-name(IN | OUT | INOUT parameter-name data-type,...) ) ---存储过程可以设定输入参数和输出参数LANGUAGE SQL ----DB2可以用多种语言编写存储过程,这里用的是纯SQLBEGIN ---开始DECLARE vID smallint; ---定义变量 和Oracle一样 DECLARE 变量名 变量的数据类型;FOR V AS SELECT BRND_CD FROM TMP_BRND_CD ---for循环 tmp_brnd_cd预先创建好DO ---循环体开始SET vID=BRND_CD; ---对vID赋值,db2可以用set赋值,也可以用values赋值,这里可以写成values(BRND_CD) into vIDINSERT INTO WWM_FORINSERT_TEST VALUES(vID); ---往wwm_forinsert_test 插入数据END FOR; -----循环体结束END @ -----存储过程结束参数语法说明
1、procedure-name: 存储过程的名字,在同一个数据库的同一模式下,不能存在存储过程名相同参数数目相同的存储过程,即使参数的类型不同也不行。
2、(IN | OUT | INOUT parameter-name data-type,...) :传入参数 IN:输入参数OUT:输出参数INOUT:作为输入输出参数 parameter-name:参数名字,在此存储过程中唯一的标识符。data-type:参数类型,可以接收SQL类型和创建的表。不支持LONG VARCHAR, LONG VARGRAPHIC, DATALINK, REFERENCE和用户自定义类型。
3、SPECIFIC specific-name:唯一的特定名称(别名),可以用存储过程名代替,这个特定名称用于dorp存储过程,或者给存储过程添加注视用,但不能调用存储过程。如果不指定,则数据库会自动生成一个yymmddhhmmsshhn时间戳的名字。推荐给出别名。
4、DYNAMIC RESULT SETS integer:指定存储过程返回结果的最大数量。存储过程中虽然没有return语句,但是却能返回结果集。
5、CONTAINS SQL, READS SQL DATA, MODIFIES SQL DATA: 指定存储过程中的SQL访问级别 CONTAINS SQL: 表示存储过程可以执行中,既不可读取 SQL 数据,也不可修改 SQL 数据。 READS SQL DATA: 表示存储过程可以执行中,可读取SQL,但不可修改 SQL 数据。 MODIFIES SQL DATA: 表示存储过程可以执行任何 SQL 语句。可以对数据库中的数据进行增加、删除和修改。
6、DETERMINISTIC or NOT DETERMINISTIC:表示存储过程是动态或者非动态的。动态的返回的值是不确定的。非动态的存储过程每次执行返回的值是相同的。
7、CALLED ON NULL INPUT:表示可以调用存储过程而不管任何的输入参数是否为NULL,并且,任何的OUT或者INOUT参数可以返回一个NULL或者非空值。检验参数是否为NULL是在过程中进行的。
8、INHERIT SPECIAL REGISTERS:表示继承专用寄存器。
9、OLD SAVEPOINT LEVEL or NEW SAVEPOINT LEVEL:建立存储点。OLD SAVEPOINT LEVEL是默认的存储点。
10、LANGUAGE SQL:指定程序的主体用的是SQL语言。
11、EXTERNAL ACTION or NO EXTERNAL ACTION:表示存储过程是否执行一些改变理数据库状态的活动,而不通过数据库管理器管。默认是 EXTERNAL ACTION。如果指定为NO EXTERNAL ACTION ,则数据库会确定最最佳优化方案。
12、PARAMETER CCSID:指定所有输出字符串数据的编码,默认为UNICODE编码数据库为PARAMETER CCSID UNICODE ,其他的数据库默认为PARAMETER CCSID 3 ASCII。
13、SQL-procedure-body:存储过程的主体

请采纳。

存储过程异常处理

【中文标题】存储过程异常处理【英文标题】:Stored procedure exception handling 【发布时间】:2011-09-29 11:47:18 【问题描述】:
SQL>  DECLARE
2    TotalUpd   NUMBER(36) := 0;
3  BEGIN
4   dbms_output.put_line ('Job Start time............... : ' || to_char(SYSDATE, '             hh24:mi:ss'));
5   UPDATE Asset SET _status = 'PROGRESS' WHERE status is null;
6   TotalUpd := SQL%ROWCOUNT;
7   dbms_output.put_line('Total Records Updated. : ' || TotalUpd);
8    COMMIT;
9   EXCEPTION
10   WHEN NO_DATA_FOUND THEN
11  dbms_output.put_line ('No more data to update.');
12  WHEN OTHERS THEN
13  dbms_output.put_line ('Error while status as SUCCESS ');
14  END ;
15  /

上述过程的结果是 作业开始时间...... : 04:41:41 更新的总记录。 : 0

但是我的预期结果是“没有更多的行要更新”必须打印,因为我已经截断了表 Asset。请告诉我哪里出错了。

【问题讨论】:

【参考方案1】:

NO_DATA_FOUND 错误不会在更新语句中引发。

如果 select 语句不返回任何内容,则会在 select into 语句中抛出。

另请参阅 select_item 下的 Tahiti on select into:*如果 SELECT INTO 语句不返回任何行,PL/SQL 将引发预定义的异常 NO_DATA_FOUND。*

如果更新语句没有更新任何内容,Oracle 不会将其视为异常,因此不会引发异常。然而,如果一个 select into 语句不能填充变量,它被认为是一个错误(因此在这种情况下 NO_DATA_EXCEPTION 被抛出(

【讨论】:

【参考方案2】:

很简单,如果没有数据,更新不会产生错误。

如果你想控制你的代码流,你需要查看TotalUpd的值

 DECLARE 
 TotalUpd   NUMBER(36) := 0;
 BEGIN
    dbms_output.put_line ('Job Start time............... : ' 
        || TO_CHAR(SYSDATE, '             hh24:mi:ss'));
    UPDATE Asset SET _status = 'PROGRESS' WHERE status IS null;
    TotalUpd := SQL%ROWCOUNT; 
    IF TotalUpd = 0 THEN
        dbms_output.put_line ('No more data to update.');
    ELSE
        dbms_output.put_line('Total Records Updated. : '
            || TotalUpd);
    END IF; 
    COMMIT; 
 EXCEPTION 
 WHEN OTHERS THEN
    dbms_output.put_line ('Error while status as SUCCESS '); 
 END; 

【讨论】:

您可以在使用 WHEN OTHERS 异常时添加 SQLERRM 和 SQLCODE。 WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('ERROR IS : ' || SQLCODE || ' : ' || SQLERRM); @Mahi007 - SQLERRM 已经包含 SQLCODE。并且通常不建议使用调试消息处理 OTHERS 异常。 请记住,我只是在回答所提出的问题,我发现最好假设功能是正确的,并且可能对输出存在依赖性。 @William Robertson - 同意 Sqlerrm 包含 sqlcode。我认为它是非生产环境。也许使用“找不到数据时”然后引发应用程序错误(-20001,)似乎是更好的选择,或者插入到错误日志表中【参考方案3】:

如果select into 不返回任何行,则抛出NO_DATA_FOUND,而不是如果在更新语句后没有更新任何行。

我建议您在更新本身之后移动处理此异常的逻辑:

IF (SQL%ROWCOUNT = 0) THEN  
  dbms_output.put_line ('No more data to update.');

【讨论】:

【参考方案4】:

认为 NO_DATA_FOUND 异常仅由您未使用的 SELECT 语句引发。尝试测试 SQL%COUNT 并根据需要输出。

【讨论】:

...我猜你是想写SQL%ROWCOUNT

以上是关于db2 存储过程 异常处理的主要内容,如果未能解决你的问题,请参考以下文章

DB2 存储过程简单示例

db2如何创建存储过程

db2 存储过程迁移方法

通过 JMeter 调用 DB2 存储过程时出现语法错误

处理 DB2 中存储过程或 SQL 中的每一行

运行存储过程时出现 db2 存储错误