【问题标题】:How do you rollback to the next iteration in a loop?如何在循环中回滚到下一次迭代?
【发布时间】:2015-11-25 03:34:46
【问题描述】:

为了更容易解释我的问题,我将粘贴我的整个代码:

drop table tst;

create table tst
(t1 number(2));

set serveroutput on
DECLARE
  TYPE vltp IS TABLE OF NUMBER(3);
  vl vltp := vltp(2,12,33,344,55,66,7,555,4);
  NUMBER_TO_BIG EXCEPTION;
  PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
  FOR i IN vl.FIRST .. vl.LAST LOOP
    INSERT INTO tst VALUES (vl(i));
    SAVEPOINT ONE;
    END LOOP;
EXCEPTION
  WHEN NUMBER_TO_BIG THEN
    ROLLBACK TO SAVEPOINT ONE;
END;
/

select * from tst;

基本上,当我将 344 插入表中时,我得到一个异常 (NUMBER_TO_BIG),我希望它回滚到循环但跳过该数字。

预期输出:

tst
-----
2
12
33
55
66
7
4

实际输出:

no rows selected

它正在回滚所有更改,而不仅仅是一个数字。

有什么想法吗?

【问题讨论】:

标签: sql database oracle exception plsql


【解决方案1】:

您应该在循环内部处理异常。一旦处理了异常,它将继续循环。

SQL> DECLARE
  TYPE vltp IS TABLE OF NUMBER(3);
  vl vltp := vltp(2,12,33,344,55,66,7,555,4);

  NUMBER_TO_BIG EXCEPTION;
  PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);

BEGIN
  FOR i IN vl.FIRST .. vl.LAST LOOP
    BEGIN
        INSERT INTO tst VALUES (vl(i));
    EXCEPTION
        WHEN NUMBER_TO_BIG THEN
        NULL;
    END;

    END LOOP;
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/

PL/SQL procedure successfully completed.


SQL> SELECT * FROM tst;

        T1
----------
         2
        12
        33
        55
        66
         7
         4

7 rows selected.

【讨论】:

  • 没有理由在此示例中包含exception when others...。您使用的任何工具都会默认为您提供错误信息。
【解决方案2】:

你应该试试这个...

drop table tst;
--create table
create table tst
(t1 number(2));

--start of code
DECLARE
  TYPE vltp IS TABLE OF NUMBER(3);
  vl vltp := vltp(2, 12, 33, 344, 55, 66, 7, 555, 4);
  NUMBER_TO_BIG EXCEPTION;
  PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
  FOR i IN vl.FIRST .. vl.LAST LOOP
    begin
      INSERT INTO tst VALUES (vl(i));
    exception
      when NUMBER_TO_BIG then
         --log exeption into log table here
        dbms_output.put_line(sqlerrm);
    end;
  END LOOP;
  commit;
exception
  when others then
    --log exeption into log table here
    dbms_output.put_line(sqlerrm);
END;

【讨论】:

    【解决方案3】:
    Hello i have illustrtaed a small snippet to replicate your scenario. Let me know if this helps.
    
    --Check for existing table with same name and dropping if already exists
    DROP TABLE tst;
    
    
    --Create Table
    CREATE TABLE tst
      (t1 NUMBER(2)
      );
    
    
    --Anonymous block to perform the task 
    SET serveroutput ON
    DECLARE
    TYPE vltp
    IS
      TABLE OF NUMBER
      (
        3
      )
      ;
      vl vltp := vltp(2,12,33,344,55,66,7,555,4);
      NUMBER_TO_BIG EXCEPTION;
      PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
    BEGIN
      FOR i IN vl.FIRST .. vl.LAST
      LOOP
      BEGIN
        INSERT INTO tst VALUES
          (vl(i)
          );
      EXCEPTION
      WHEN NUMBER_TO_BIG THEN
      NULL;
      dbms_output.put_line('skipping the value');
      END;
      END LOOP;
      COMMIT;
    END;
    

    【讨论】:

    • 所以据我了解,在我的代码中,当它遇到异常时,它会沿着代码向下直到找到如何处理它。在你遇到异常时,因为它在循环中,所以它把它当作一种“if”语句。所以它遇到了一个异常,说:如果异常什么都不做。还是我认为这一切都错了?
    • 是的,您的理解是正确的。由于循环本身就存在异常处理,因此它会跳过异常值并继续循环。
    猜你喜欢
    • 2021-07-11
    • 2014-01-07
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 2010-12-23
    相关资源
    最近更新 更多