sql >> Databasteknik >  >> RDS >> Oracle

Oracle som lösning på muterande tabeller

Oracles muterande triggerfel uppstår när en trigger refererar till tabellen som äger triggern, vilket resulterar i meddelandet "ORA-04091:tabellnamnet muterar, triggern/funktionen kanske inte ser det".

Låt oss ta en titt på de befintliga lösningarna.

Den första, genom paketet, är gammal och verkar vara effektiv, men det tar mycket tid att förbereda och köra den. Den andra är enkel och utförs med hjälp av sammansatta triggers.

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;

När Splinter muterar från en råtta till en sensei måste målarna automatiskt förvandlas till ninja. Denna utlösare verkar vara lämplig:

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;

Men när du uppdaterar posten:

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

Följande fel uppstår:

ORA-04091:Tabell SCOTT.TURTLES muterar, trigger/funktion kanske inte ser den

Låt oss ta bort denna utlösare:

drop trigger tr_turtles_bue;

Metoden 1: Använda paketet och utlösaren på instruktionsnivå.

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

Metoden 2: Använder sammansatta DML-utlösare (tillgänglig från och med 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;

Låt oss prova följande:

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

Även om du stod inför ett mer komplext fall av mutation, kan du använda den ovan nämnda idén som en lösning. I utlösaren på instruktionsnivån, till skillnad från utlösaren på radnivån, sker ingen mutation. Du kan använda antingen variabler (taggar, låsningar, PL SQL-tabeller) i ett extra paket eller variabler som är globala för alla sektioner av den sammansatta utlösaren, vilket är att föredra från och med versionen Oracle 11g. Så nu vet du också kung fu.

Du kan hitta ytterligare information om triggers på:Compound DML Triggers

Lägg gärna till kommentarer.


  1. SQL Server Inloggningsfel:Inloggning misslyckades för användaren 'NT AUTHORITY\SYSTEM'

  2. Få tabellkolumnnamn i MySQL?

  3. Hur kan jag hitta alla tabeller i MySQL med specifika kolumnnamn i dem?

  4. Automatisk ökning för Oracle