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

Oracle som løsning af muterende tabeller

Oracle-mutationstriggerfejlen opstår, når en trigger refererer til den tabel, der ejer triggeren, hvilket resulterer i meddelelsen "ORA-04091:tabelnavnet muterer, triggeren/funktionen ser den muligvis ikke".

Lad os se på de eksisterende løsninger.

Den første, gennem pakken, er gammel og ser ud til at være effektiv, men det tager meget tid at forberede og køre den. Den anden er enkel og udføres ved hjælp af sammensatte triggere.

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 muterer fra en rotte til en sensei, bliver malerne automatisk nødt til at blive til ninjaer. Denne trigger ser ud til at være egnet:

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 opdaterer posten:

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

Følgende fejl opstår:

ORA-04091:tabel SCOTT.TURTLES muterer, trigger/funktion kan muligvis ikke se den

Lad os slette denne trigger:

drop trigger tr_turtles_bue;

Metode 1: Brug af pakken og udløseren på instruktionsniveau.

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

Metode 2: Brug af sammensatte DML-triggere (tilgængelig fra 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;

Lad os prøve følgende:

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

Selvom du stod over for et mere komplekst tilfælde af mutation, kan du bruge ovennævnte idé som en løsning. I instruktions-niveau-triggeren, i modsætning til række-niveau-triggeren, sker der ingen mutation. Du kan bruge enten variabler (tags, latches, PL SQL-tabeller) i en ekstra pakke eller variabler, der er globale for alle sektioner af den sammensatte trigger, hvilket er at foretrække at starte med versionen Oracle 11g. Så nu kender du også kung fu.

Du kan finde yderligere oplysninger om udløsere på:Sammensatte DML-udløsere

Du er velkommen til at tilføje eventuelle kommentarer.


  1. PostgreSQL næste værdi af sekvenserne?

  2. Beregning af forskel mellem to tidsstempler i Oracle i millisekunder

  3. Sammenføjning af resultater fra to separate databaser

  4. ORA-12557 TNS:protokoladapter kan ikke indlæses