Oracle
 sql >> Database >  >> RDS >> Oracle

Oracle come soluzione alternativa alle tabelle mutanti

L'errore di trigger mutante Oracle si verifica quando un trigger fa riferimento alla tabella che possiede il trigger, risultando nel messaggio "ORA-04091:il nome della tabella sta mutando, il trigger/la funzione potrebbe non vederlo".

Diamo un'occhiata alle soluzioni alternative esistenti.

Il primo, tramite il pacchetto, è antico e sembra essere efficace, tuttavia ci vuole molto tempo per prepararlo ed eseguirlo. Il secondo è semplice ed eseguito utilizzando trigger composti.

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;

Quando Splinter si trasforma da topo in un sensei, i pittori dovranno trasformarsi automaticamente in ninja. Questo trigger sembra essere adatto:

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;

Tuttavia, durante l'aggiornamento del record:

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

Si verifica il seguente errore:

ORA-04091:la tabella SCOTT.TURTLES sta mutando, il trigger/la funzione potrebbe non vederlo

Eliminiamo questo trigger:

drop trigger tr_turtles_bue;

Il metodo 1: Utilizzo del pacchetto e del trigger a livello di istruzione.

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;
/

Il metodo 2: Utilizzo di trigger DML composti (disponibili a partire da 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;

Proviamo quanto segue:

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

Anche se hai affrontato un caso più complesso di mutazione, puoi usare l'idea sopra menzionata come soluzione alternativa. Nel trigger a livello di istruzione, a differenza del trigger a livello di riga, non si verifica alcuna mutazione. È possibile utilizzare variabili (tag, latch, tabelle PL SQL) in un pacchetto aggiuntivo o variabili globali per tutte le sezioni del trigger composto, che è preferibile a partire dalla versione Oracle 11g. Quindi ora conosci anche il kung fu.

Puoi trovare ulteriori informazioni sui trigger su:Trigger DML composti

Sentiti libero di aggiungere qualsiasi commento.