Oracle 11g FORALL和BULK DELETE Bug?

时间:2014-05-07 09:47:22

标签: oracle plsql oracle11g

请你帮我解决以下问题:

我使用的是Oracle Database 11g企业版11.1.0.7.0版 - 64位生产版,我需要删除一个表。
由于性能原因,我试图使用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仍未删除。

谢谢!

1 个答案:

答案 0 :(得分:0)

将约束设置为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子句,即从底部开始 从顶部
  • <>ALL ()等于NOT IN ()
  • 您也可以使用 START WITH ID IN (4,6)