Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle als Workaround für mutierende Tabellen

Der Oracle-Mutating-Trigger-Fehler tritt auf, wenn ein Trigger auf die Tabelle verweist, die den Trigger besitzt, was zur Meldung „ORA-04091:Tabellenname mutiert, Trigger/Funktion kann ihn nicht sehen“ führt.

Sehen wir uns die bestehenden Problemumgehungen an.

Der erste, durch das Paket, ist uralt und scheint effektiv zu sein, es dauert jedoch viel Zeit, ihn vorzubereiten und auszuführen. Der zweite ist einfach und wird mit zusammengesetzten Triggern ausgeführt.

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;

Wenn Splinter von einer Ratte zu einem Sensei mutiert, müssen sich die Maler automatisch in Ninja verwandeln. Dieser Trigger scheint geeignet zu sein:

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;

Beim Aktualisieren des Datensatzes jedoch:

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

Der folgende Fehler tritt auf:

ORA-04091:Tabelle SCOTT.TURTLES mutiert, Auslöser/Funktion sieht sie möglicherweise nicht

Löschen wir diesen Trigger:

drop trigger tr_turtles_bue;

Die Methode 1: Verwenden des Pakets und des Triggers auf Anweisungsebene.

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

Die Methode 2: Verwenden zusammengesetzter DML-Trigger (verfügbar ab 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;

Versuchen wir Folgendes:

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

Selbst wenn Sie mit einem komplexeren Mutationsfall konfrontiert waren, können Sie die oben erwähnte Idee als Problemumgehung verwenden. Beim Trigger auf Befehlsebene tritt im Gegensatz zum Trigger auf Zeilenebene keine Mutation auf. Sie können entweder Variablen (Tags, Latches, PL-SQL-Tabellen) in einem zusätzlichen Paket verwenden oder Variablen, die für alle Abschnitte des Compound-Triggers global sind, was ab der Version Oracle 11g zu bevorzugen ist. Jetzt kennst du dich also auch mit Kung Fu aus.

Weitere Informationen zu Triggern finden Sie unter:Zusammengesetzte DML-Trigger

Fühlen Sie sich frei, Kommentare hinzuzufügen.