我正在尝试从表中删除很多行。我想尝试将要删除的行放入游标的方法,然后继续对游标的每一行进行提取、删除、提交,直到它为空。
在下面的代码中,我们是 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;
最佳答案
为什么要批量提交?那只会减慢您的处理速度。除非有其他 session 试图修改您尝试删除的行(由于其他原因这似乎有问题),否则最有效的方法是简单地使用单个 DELETE 删除数据,即
DELETE FROM uiv_response_income uri
WHERE EXISTS(
SELECT 1
FROM (<<bulk_delete_dup query>>) bdd
WHERE bdd.rowid = uri.rowid
)
当然,根据游标背后的查询的设计方式,很可能有更优的编写方式。
如果你真的想消除 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.
但是请注意,由于您必须锁定该行(使用 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
如果删除锁定并避免使用 WHERE CURRENT OF 语法,根据从游标中获取的值删除数据,则可能不会出现运行时错误。但是,这仍然是跨提交进行提取,这是一种糟糕的做法,并且从根本上增加了您至少间歇性地获得 ORA-01555: snapshot too old 错误的几率。与单个 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.
当然,您还必须确保您的进程可以重新启动,以防您处理某些行子集并且在进程终止之前有一些未知数量的临时提交。如果
DELETE
足以导致不再从游标返回行,您的进程可能已经可以重新启动。但一般来说,如果您尝试将单个操作分解为多个事务,则这是一个问题。
关于sql - 如何从游标中获取、删除、提交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5757268/