PL/SQL 异常处理

Posted

技术标签:

【中文标题】PL/SQL 异常处理【英文标题】:PL/SQL exception handling 【发布时间】:2016-01-22 07:11:28 【问题描述】:

我是 pl/sql 编程的新手,过去 2 小时一直在尝试解决这个问题

这是我的代码

CREATE OR REPLACE PROCEDURE xx_upd_new_code AS   

  CURSOR c1 IS
    SELECT
      eite.t_ep_item_ep_id,
      bite.main_item
    FROM bidw.item@demantra bite,
      t_ep_item eite
    WHERE bite.item_code = eite.item
          AND bite.main_item = bite.old_code
          AND bite.current_flag = 1
          AND bite.main_item IS NOT NULL;

  a1 c1%ROWTYPE;

  BEGIN
    xx_dbex('Starts.', 'xx_upd_new_code', 'XX');

    OPEN c1;
    LOOP
      FETCH c1 INTO a1;
      EXIT WHEN c1%NOTFOUND;

      xx_dbex('Item: ' || a1.main_item, 'xx_upd_new_code', 'XX');

      UPDATE t_ep_item
      SET item = a1.main_item
      WHERE t_ep_item_ep_id = a1.t_ep_item_ep_id;

      COMMIT;

      xx_dbex('Ends.', 'xx_upd_new_code', 'XX');
    END LOOP;

    EXCEPTION 
    WHEN OTHERS THEN xx_dbex('Error.', 'xx_upd_new_code', 'XX');   
  END xx_upd_new_code;

只要出现错误,程序就会结束,但我希望它移至下一项。 xx_debex 是一个存储日志的过程。

我一直在谷歌搜索,我发现我可以写两个异常&如果条件不满足可以引发异常。我试过这个但它会抛出一个错误 必须声明标识符 a 必须声明标识符项

CREATE OR REPLACE PROCEDURE xx_upd_new_code AS   

  CURSOR c1 IS
    SELECT
      eite.t_ep_item_ep_id,
      bite.main_item
    FROM bidw.item@demantra bite,
      t_ep_item eite,
      items ite
    WHERE bite.item_code = eite.item
          AND bite.main_item = bite.old_code
          AND bite.current_flag = 1              
          AND bite.main_item IS NOT NULL;

  a1 c1%ROWTYPE;

  BEGIN
    xx_dbex('Starts.', 'xx_upd_new_code', 'XX');

    OPEN c1;
    LOOP
      FETCH c1 INTO a1;
      EXIT WHEN c1%NOTFOUND;

      IF item != a1.main_item THEN
        xx_dbex('Item: ' || a1.main_item, 'xx_upd_new_code', 'XX');

        UPDATE t_ep_item
        SET item = a1.main_item
        WHERE t_ep_item_ep_id = a1.t_ep_item_ep_id;
        COMMIT;

        xx_dbex('Ends.', 'xx_upd_new_code', 'XX');          
      ELSE
        RAISE a;
      END IF;

    END LOOP;

    EXCEPTION 
      WHEN a THEN xx_dbex('Error.', 'xx_upd_new_code', 'XX');
      WHEN OTHERS THEN NULL;   
  END xx_upd_new_code;

另外,它被写在某个地方,我可以把它写成两个不同的块

CREATE OR REPLACE PROCEDURE xx_upd_new_code AS

  CURSOR c1 IS
    SELECT
      eite.t_ep_item_ep_id,
      bite.main_item
    FROM bidw.item@demantra bite,
      t_ep_item eite
    WHERE bite.item_code = eite.item
          AND bite.main_item = bite.old_code
          AND bite.current_flag = 1
          AND bite.main_item IS NOT NULL;

  a1 c1%ROWTYPE;

  BEGIN
    xx_dbex('Starts.', 'xx_upd_new_code', 'XX');

    BEGIN

      EXCEPTION
      WHEN OTHERS THEN xx_dbex('Error', 'xx_upd_new_code', 'XX');
    END;

    OPEN c1;
    LOOP
      FETCH c1 INTO a1;
      EXIT WHEN c1%NOTFOUND;

      xx_dbex('Item: ' || a1.main_item, 'xx_upd_new_code', 'XX');
      UPDATE t_ep_item
      SET item = a1.main_item
      WHERE t_ep_item_ep_id = a1.t_ep_item_ep_id;
      COMMIT;

    END LOOP;

    EXCEPTION WHEN OTHERS THEN
    xx_dbex('END', 'xx_upd_new_code', 'XX'); 
  END xx_upd_new_code;

我还是想不通。

【问题讨论】:

xx_dbex 程序是做什么的? 【参考方案1】:

将光标循环分成两部分/块。第一个将用于调用日志记录过程的部分,另一个将用于更新表的部分。您的代码主体应如下所示:

  BEGIN
     Open C1; 
     loop
        fetch C1 into A1;
        exit when C1%NOTFOUND
        BEGIN
           xx_dbex('Item: '||a1.main_item ,'xx_upd_new_code', 'XX');
        END;
        BEGIN
           UPDATE t_ep_item 
           SET item = a1.main_item
           where t_ep_item_ep_id=a1.t_ep_item_ep_id;
           COMMIT;
           xx_dbex('Ends.','xx_upd_new_code', 'XX');
        EXCEPTION
           WHEN OTHERS THEN 
              xx_dbex('Ends.','ERROR', 'XX');
        END;
  END LOOP;

希望你能明白

【讨论】:

【参考方案2】:

只需将循环内的语句封装到一个新的 pl/sql 块中,如下所示:

loop
 begin
  fetch ...
 exception
  when ...
 end;
end loop;

顺便说一句。记录过程应使用pragma_autonomous_transactioncommit 独立于当前事务结果。

【讨论】:

以上是关于PL/SQL 异常处理的主要内容,如果未能解决你的问题,请参考以下文章

PL\SQL 函数之间的异常处理

PL/SQL 异常处理

PL/SQL 异常处理

处理过程 PL/SQL 的异常

PL/SQL系统定义的异常操作实例讲解

Oracle的PL_SQL的异常处理