Oracle
 sql >> Base de données >  >> RDS >> Oracle

comment récupérer, supprimer, valider à partir du curseur

Pourquoi voulez-vous vous engager par lots ? Cela ne fera que ralentir votre traitement. À moins qu'il n'y ait d'autres sessions qui essaient de modifier les lignes que vous essayez de supprimer, ce qui semble problématique pour d'autres raisons, l'approche la plus efficace serait simplement de supprimer les données avec un seul DELETE, c'est-à-dire

DELETE FROM uiv_response_income uri
 WHERE EXISTS( 
    SELECT 1
      FROM (<<bulk_delete_dup query>>) bdd
     WHERE bdd.rowid = uri.rowid
  )

Bien sûr, il peut y avoir une manière plus optimale d'écrire cela en fonction de la conception de la requête derrière votre curseur.

Si vous voulez vraiment éliminer le BULK COLLECT (ce qui ralentira considérablement le processus), vous pouvez utiliser la syntaxe WHERE CURRENT OF pour effectuer le 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.

Sachez cependant que puisque vous devez verrouiller la ligne (avec la clause FOR UPDATE), vous ne pouvez pas mettre de commit dans la boucle. Faire un commit libérerait les verrous que vous aviez demandés avec le FOR UPDATE et vous obtiendrez une ORA-01002 :erreur de récupération hors séquence

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

Vous ne pouvez pas obtenir d'erreur d'exécution si vous supprimez le verrouillage et évitez la syntaxe WHERE CURRENT OF, en supprimant les données en fonction de la ou des valeurs que vous avez extraites du curseur. Cependant, cela continue de faire une récupération à travers la validation, ce qui est une mauvaise pratique et augmente radicalement les chances que vous obteniez, au moins par intermittence, une erreur ORA-01555 :instantané trop ancien. Il sera également extrêmement lent par rapport à l'instruction SQL unique ou à l'option 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.

Bien sûr, vous devez également vous assurer que votre processus est redémarrable au cas où vous traiteriez un sous-ensemble de lignes et que vous auriez un nombre inconnu de validations intermédiaires avant que le processus ne meure. Si le DELETE est suffisant pour que la ligne ne soit plus renvoyée par votre curseur, votre processus est probablement déjà redémarrable. Mais en général, c'est un problème si vous essayez de diviser une seule opération en plusieurs transactions.