0

我正在编写一些代码,这些代码会将数十亿数据从一个表复制到另一个表,并且我们不希望该过程在出现异常时停止。所以我把脚本放在(不是把 100% 可编译的语法)

dml_errors      exception;
errors          number;
error_count     number;
pragma exception_init (dml_errors, -24381);

---------
open cursor;
begin loop;
   fetch cursor bulk collect into tbl_object limit batch_size;
   exit when tbl_object.count = 0;
   -- perform business logic
   begin
       forall in tbl_object save exceptions;
          insert into table;
          tbl_object.delete;
   exception
       when dml_errors then
                errors      :=  sql%bulk_exceptions.count;
                error_count :=  error_count + errors;
                insert into log_table (tstamp, line) values (sysdate, SUBSTR('[pr_procedure_name:'||r_guid||'] Batch # '||batch_number - 1||' had '||errors||' errors',1,300));
   end;
end loop;
close cursor;
end procedure;

现在基于这个伪代码我有2个问题

  1. 我正在 forall 循环中删除我的收藏。如果出现异常并且我决定从 dml_errors 块中的集合中获取一些信息,我会在其中包含集合元素吗?如果是,那么在登录后删除它们是否安全?
  2. 由于我将我的 forall 保留在 begin-exception-end 块中,它会继续迭代吗?
4

1 回答 1

1

你确定你需要在这里使用 PL/SQL 吗?除非您在业务逻辑中进行大量未向我们展示的无法在 SQL 中完成的处理,否则我倾向于使用DML 错误日志记录。这将更有效率,更少的代码,并为您提供更好的日志记录。

DBMS_ERRLOG.CREATE_ERROR_LOG( 'DESTINATION_TABLE' );

INSERT INTO destingation_table( <<columns>> )
  SELECT <<columns>>
    FROM source_table
  LOG ERRORS 
  REJECT LIMIT UNLIMITED;

我看不出有任何理由从您的tbl_object收藏中删除。这似乎没有给你带来任何好处。这只是花费一些时间。如果您的缩进表示您预期的控制流,那么您认为这delete是循环的一部分——forall这是不正确的。只有insert是 的一部分foralldelete是单独的操作。

如果您的第二个问题是“如果在迭代 N 中引发异常,循环是否仍会执行第 N+1 次获取”,答案是肯定的,它会。

需要注意的一件事 - 由于error_count未初始化,因此它将始终为 NULL。您需要将其初始化为 0 以记录错误总数。

于 2013-09-06T04:41:45.333 回答