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

Oracle comme solution de contournement des tables en mutation

L'erreur de déclencheur de mutation Oracle se produit lorsqu'un déclencheur fait référence à la table qui possède le déclencheur, ce qui entraîne le message "ORA-04091 :le nom de la table est en train de muter, le déclencheur/la fonction peut ne pas le voir".

Examinons les solutions de contournement existantes.

Le premier, à travers le package, est ancien et semble être efficace, cependant, il faut beaucoup de temps pour le préparer et l'exécuter. Le second est simple et exécuté à l'aide de déclencheurs composés.

create table turtles 
as
select 'Splinter' name, 'Rat' essence from dual union all
select 'Leonardo', 'Painter' from dual union all
select 'Rafael', 'Painter' from dual union all
select 'Michelangelo', 'Painter'  from dual union all
select 'Donatello', 'Painter'  from dual;

Lorsque Splinter passe d'un rat à un sensei, les peintres devront automatiquement se transformer en ninja. Ce déclencheur semble convenir :

create or replace trigger tr_turtles_bue
before update of essence
on turtles
for each row
when (
  new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei'
)
begin
  update turtles
     set essence = 'Ninja'
   where essence = 'Painter';  
end;

Cependant, lors de la mise à jour de la fiche :

update turtles
   set essence = 'Sensei'
 where name = 'Splinter'

L'erreur suivante se produit :

ORA-04091 :la table SCOTT.TURTLES est en mutation, le déclencheur/la fonction peut ne pas la voir

Supprimons ce déclencheur :

drop trigger tr_turtles_bue;

La méthode 1 : Utilisation du package et du déclencheur au niveau de l'instruction.

create or replace package pkg_around_mutation 
is
  bUpdPainters boolean;
  procedure update_painters;  
end pkg_around_mutation;
/

create or replace package body pkg_around_mutation
is
  procedure update_painters
  is
  begin   
    if bUpdPainters then
      bUpdPainters := false;
      update turtles
         set essence = 'Ninja'
       where essence = 'Painter';
    end if;
  end;  
end pkg_around_mutation;
/

create or replace trigger tr_turtles_bue
before update of essence
on turtles
for each row
when (
  new.name = 'Splinter' and old.essence = 'Rat' and new.essence = 'Sensei' 
)
begin
  pkg_around_mutation.bUpdPainters := true;  
end tr_turtles_bue; 
/

create or replace trigger tr_turtles_bu
after update
on turtles
begin
  pkg_around_mutation.update_painters;  
end tr_turtles_bu;
/

La méthode 2 : Utilisation de déclencheurs DML composés (disponibles à partir d'Oracle 11g).

create or replace trigger tr_turtles_ue
  for update of essence
  on turtles
  compound trigger
    bUpdPainters  boolean;
 
  before each row is
  begin
    if :new.name = 'Splinter' and :old.essence = 'Rat' and :new.essence = 'Sensei' then
      bUpdPainters := true;
    end if;
  end before each row;
  
  after statement is
  begin
    if bUpdPainters then
      update Turtles
         set essence = 'Ninja'
       where essence = 'Painter';
    end if;
  end after statement;
end tr_turtles_ue;

Essayons ce qui suit :

update turtles
   set essence = 'Sensei'
 where name = 'Splinter'

Même si vous avez été confronté à un cas de mutation plus complexe, vous pouvez utiliser l'idée mentionnée ci-dessus comme solution de contournement. Dans le déclencheur au niveau de l'instruction, contrairement au déclencheur au niveau de la ligne, aucune mutation ne se produit. Vous pouvez utiliser soit des variables (balises, verrous, tables PL SQL) dans un package supplémentaire, soit des variables globales pour toutes les sections du déclencheur composé, ce qui est préférable à partir de la version Oracle 11g. Alors, maintenant, vous connaissez aussi le kung-fu.

Vous pouvez trouver des informations supplémentaires sur les déclencheurs à :Déclencheurs DML composés

N'hésitez pas à ajouter des commentaires.