如何从游标中获取,删除,提交

Omn*_*ent 6 sql oracle plsql

我试图从表中删除很多行.我想尝试将我想要删除的行放入游标,然后继续对游标的每一行进行获取,删除,提交,直到它为空.

在下面的代码中,我们是fetching行并将它们放在一个TYPE.

如何修改以下代码以从图片中删除TYPE,只需fetch,delete,commit对光标本身进行操作即可.

    OPEN bulk_delete_dup;
    LOOP
        FETCH bulk_delete_dup BULK COLLECT INTO arr_inc_del LIMIT c_rows;

        FORALL i IN arr_inc_del.FIRST .. arr_inc_del.LAST
              DELETE FROM UIV_RESPONSE_INCOME 
              WHERE ROWID = arr_inc_del(i);

        COMMIT;
        arr_inc_del.DELETE;
        EXIT WHEN bulk_delete_dup%NOTFOUND;
    END LOOP;
    arr_inc_del.DELETE;
    CLOSE bulk_delete_dup;
Run Code Online (Sandbox Code Playgroud)

Jus*_*ave 17

你为什么要批量提交?这只会减慢您的处理速度.除非有其他会话尝试修改您尝试删除的行,这似乎有其他原因的问题,最有效的方法是简单地用一个DELETE删除数据,即

DELETE FROM uiv_response_income uri
 WHERE EXISTS( 
    SELECT 1
      FROM (<<bulk_delete_dup query>>) bdd
     WHERE bdd.rowid = uri.rowid
  )
Run Code Online (Sandbox Code Playgroud)

当然,根据光标背后的查询设计方式,可能有更优化的编写方式.

如果你真的想要消除BULK COLLECT(这将大大减慢进程),你可以使用WHERE CURRENT OF语法来执行DELETE

SQL> create table foo
  2  as
  3  select level col1
  4    from dual
  5  connect by level < 10000;

Table created.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10    end loop;
 11* end;
SQL> /

PL/SQL procedure successfully completed.
Run Code Online (Sandbox Code Playgroud)

但请注意,由于必须锁定行(使用FOR UPDATE子句),因此无法在循环中提交提交.执行提交将释放您使用FOR UPDATE请求的锁定,并且您将获得ORA-01002:fetch out of sequence错误

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo for update;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where current of c1;
 10      commit;
 11    end loop;
 12* end;
SQL> /
declare
*
ERROR at line 1:
ORA-01002: fetch out of sequence
ORA-06512: at line 7
Run Code Online (Sandbox Code Playgroud)

如果删除锁定并避免使用WHERE CURRENT OF语法,则可能不会收到运行时错误,并根据从游标中提取的值删除数据.但是,这仍然是在提交中进行提取,这是一种糟糕的做法,并且从根本上会间歇地获得ORA-01555:快照太旧的错误,从根本上增加了几率.与单个SQL语句或BULK COLLECT选项相比,它也将非常缓慢.

SQL> ed
Wrote file afiedt.buf

  1  declare
  2    cursor c1 is select * from foo;
  3    l_rowtype c1%rowtype;
  4  begin
  5    open c1;
  6    loop
  7      fetch c1 into l_rowtype;
  8      exit when c1%notfound;
  9      delete from foo where col1 = l_rowtype.col1;
 10      commit;
 11    end loop;
 12* end;
SQL> /

PL/SQL procedure successfully completed.
Run Code Online (Sandbox Code Playgroud)

当然,您还必须确保您的进程可以重新启动,以防您在进程终止之前处理某些行子集并具有一些未知数量的临时提交.如果DELETE足以导致不再从游标返回行,则您的进程可能已经可以重新启动.但总的来说,如果您尝试将单个操作分解为多个事务,那么这是一个问题.