如何在循环中回滚到下一次迭代?
Posted
技术标签:
【中文标题】如何在循环中回滚到下一次迭代?【英文标题】: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 进行插入会更加简单高效,并使用 LOG ERRORS 子句来处理被拒绝的行:docs.oracle.com/cd/B19306_01/server.102/b14200/… 【参考方案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”语句。所以它遇到了一个异常,说:如果异常什么都不做。还是我认为这一切都错了? 是的,您的理解是正确的。由于循环本身就存在异常处理,因此它会跳过异常值并继续循环。以上是关于如何在循环中回滚到下一次迭代?的主要内容,如果未能解决你的问题,请参考以下文章
当单值事件或事务的嵌套 ValueEventListener 失败时,如何在 Firebase Realtime DB for Android 中回滚到以前的状态?
NodeJS,如何强制异步 for 循环在传递到下一次迭代之前等待 HTTP 请求解决,这样我们就不会收到 EMFILE 错误?
如何在 googleplay 中回滚 apk 版本? [复制]