Por que você quer se comprometer em lotes? Isso só vai retardar o seu processamento. A menos que haja outras sessões que estejam tentando modificar as linhas que você está tentando excluir, o que parece problemático por outros motivos, a abordagem mais eficiente seria simplesmente excluir os dados com um único DELETE, ou seja,
DELETE FROM uiv_response_income uri
WHERE EXISTS(
SELECT 1
FROM (<<bulk_delete_dup query>>) bdd
WHERE bdd.rowid = uri.rowid
)
É claro que pode haver uma maneira mais otimizada de escrever isso, dependendo de como a consulta por trás do cursor foi projetada.
Se você realmente deseja eliminar o BULK COLLECT (o que diminuirá substancialmente o processo), você pode usar a sintaxe WHERE CURRENT OF para fazer o 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.
Esteja ciente, no entanto, que como você precisa bloquear a linha (com a cláusula FOR UPDATE), você não pode colocar um commit no loop. Fazer um commit liberaria os bloqueios que você solicitou com o FOR UPDATE e você obteria um erro 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
Você pode não obter um erro de tempo de execução se remover o bloqueio e evitar a sintaxe WHERE CURRENT OF, excluindo os dados com base no(s) valor(es) obtido(s) do cursor. No entanto, isso ainda está fazendo uma busca no commit, o que é uma prática ruim e aumenta radicalmente as chances de você, pelo menos intermitentemente, obter um erro ORA-01555:snapshot too old. Também será dolorosamente lento em comparação com a única instrução SQL ou a opção 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.
Claro, você também precisa garantir que seu processo seja reiniciável caso você processe algum subconjunto de linhas e tenha um número desconhecido de commits temporários antes que o processo morra. Se o
DELETE
é suficiente para fazer com que a linha não seja mais retornada do seu cursor, seu processo provavelmente já pode ser reiniciado. Mas, em geral, isso é uma preocupação se você tentar dividir uma única operação em várias transações.