【问题标题】:Oracle 11g FORALL and BULK DELETE Bug?Oracle 11g FORALL 和 BULK DELETE 错误?
【发布时间】:2014-06-24 05:24:15
【问题描述】:

您能帮我解决以下问题吗:

我正在使用 Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production,我需要删除一个表。
由于性能原因,我尝试使用 forall 将其删除,但这无法正常工作。假设我有下表:

create table test
 (id number (4) not null,
  parent_id number(4),
  constraint id_pk primary key (id),
  constraint fk_id
  foreign key (parent_id)
  references test(id)
 );

有以下记录:

ID         PARENT_ID  
---------- ---------- 
     1           
     2          3 
     3           
     4          5 
     5           
     6          7 
     7           
     8 

对于删除,我使用以下程序:

declare
   l_idx       number;
   l_err_cnt   number;

   type tp_tab_num is table of number
      index by binary_integer;

   a_pid       tp_tab_num;

   cursor c_pid
   is
      select     id
            from test
           where id <> 4
      start with parent_id is null
      connect by prior id = parent_id
      order by level desc, id;
begin
   open c_pid;

   fetch c_pid
   bulk collect into a_pid;

   begin
      forall i in a_pid.first .. a_pid.last save exceptions

         delete from test
               where id = a_pid (i);
   exception
      when others then
         l_err_cnt := sql%bulk_exceptions.count;
   end;

   close c_pid;

   for i in 1 .. l_err_cnt loop
      l_idx := sql%bulk_exceptions (i).error_index;
      dbms_output.put_line (   'Index:' || sql%bulk_exceptions (i).error_index
                            || ' Code: ' || sql%bulk_exceptions (i).error_code
                            || ' Message: ' || sqlerrm (-sql%bulk_exceptions (i).error_code)
                            || ' Pid: ' || a_pid (l_idx)
                           );
   end loop;
end;   

forall 的问题在于,如果未从表中删除子记录(例如,由于对其他表的外键约束 - 在我们的案例中,ID 为 4 的记录已从删除游标中排除) 尽管我正在使用保存异常,但 forall 不会删除未删除的子项的父项之后的任何其他记录。

删除过程的输出是:

Index:5 Code: 2292 Message: ORA-02292: integrity constraint (.) violated - child record found Pid: 5 -- Correct: due to constraint fk_id 

Index:6 Code: 2292 Message: ORA-02292: integrity constraint (.) violated - child record found Pid: 7 -- Incorrect: child with ID = 6 is already deleted 

Index:7 Code: 2292 Message: ORA-02292: integrity constraint (.) violated - child record found Pid: 8 -- Incorrect: ID 8 has no children 

请注意,如果我使用 for 循环而不是 forall,它可以正常工作。只有 ID 4 和 5 仍未删除。

谢谢!

【问题讨论】:

  • 嗨,我的真实情况是示例中的表测试也有其他表的外键。如果这些没有被删除,我不能从测试中删除记录。因此,如果我使用单个删除它会崩溃。除了保存例外,我只删除我被允许的内容。
  • 有问题的外键约束是与表本身的关系。因此,您是否违反约束取决于处理行的顺序。我不知道 FORALL 是否坚持任何给定的顺序。
  • 您好,我找不到任何关于 forall 坚持给定顺序的参考资料。但我在桌子上测试过。因此,如果您不排除记录 ID 4 并按级别 desc 保留订单,则删除工作正常。但是,如果您按级别 asc 更改顺序,则脚本将失败并显示 ora 02292。因此,似乎 forall 保持顺序计数。所以我的问题不是来自order by。我仍然认为是一个 oracle 错误。

标签: oracle plsql oracle11g


【解决方案1】:

当您将约束设置为DEFERRED 时,它应该可以工作。那么它只适用于COMMIT之后。

或使用单个 DELETE 语句:

delete from test
where id =any 
   (select id
    from test
    where id <> 4
    start with parent_id is null
    connect by prior id = parent_id);

编辑:

反过来做:

DELETE FROM TEST
WHERE ID <>ALL 
   (SELECT ID
    FROM TEST
    START WITH ID = 4
    CONNECT BY ID = PRIOR parent_id);

一些注意事项:

  • 我更改了CONNECT BY 子句,即从底部开始 从上到下
  • &lt;&gt;ALL () 等于 NOT IN ()
  • 您还可以使用 START WITH ID IN (4,6)

【讨论】:

  • 您好,谢谢您的回答。我将 fk_id 约束设置为最初延迟可延迟并且脚本运行时没有错误。但是在提交时,我得到 ORA-02091:事务回滚 ORA-02292:违反完整性约束 (FK_ID) - 发现子记录 我认为这是因为我留在了 ID = 4 的表记录中并且脚本删除了它父 ID=5 并且提交失败。事实上,我想删除除 ID=4 之外的所有其他记录,因为它与其他表有关,这就是我跳过它的原因,它是 ID=5 的父项​​。
  • 我尝试了单选但它没有工作它崩溃了:17:45:19 ORA-02292: 违反完整性约束 (FK_ID) - 找到子记录
  • 您好,现在删除工作,但不幸的是无法知道 start with 子句的 ID。在我的真实情况下 ID = 4 不是 deleteld 因为它在其他表中有子表。因此,如果表测试中的孩子 ID 在其他表中有孩子,我不能将它们与表测试中的父母一起删除。所以我不知道在 start with 子句中使用哪些 ID。
猜你喜欢
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多