sql >> Databáze >  >> RDS >> Oracle

Oracle jako řešení mutujících tabulek

Chyba spouštěče mutování Oracle nastane, když spouštěč odkazuje na tabulku, která spouštěč vlastní, což má za následek zprávu „ORA-04091:název tabulky mutuje, spouštěč/funkce jej nemusí vidět“.

Pojďme se podívat na stávající zástupná řešení.

První z nich, prostřednictvím balíčku, je starověký a zdá se být účinný, ale jeho příprava a provoz zabere mnoho času. Druhý je jednoduchý a provádí se pomocí složených spouštěčů.

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;

Když Splinter zmutuje z krysy na senseie, malíři se budou muset automaticky proměnit v ninju. Tento spouštěč se zdá být vhodný:

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;

Při aktualizaci záznamu však:

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

Dojde k následující chybě:

ORA-04091:tabulka SCOTT.TURTLES mutuje, spouštěč/funkce ji nemusí vidět

Smažeme tento spouštěč:

drop trigger tr_turtles_bue;

Metoda 1: Pomocí balíčku a spouštěče na úrovni instrukcí.

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

Metoda 2: Použití složených spouštěčů DML (dostupné od 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;

Zkusme následující:

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

I když jste čelili složitějšímu případu mutace, můžete výše zmíněný nápad použít jako řešení. Ve spouštěči na úrovni instrukce, na rozdíl od spouštěče na úrovni řádku, nedochází k žádné mutaci. Můžete použít buď proměnné (tagy, latche, PL SQL tabulky) v dalším balíčku, nebo proměnné, které jsou globální pro všechny sekce složeného spouštěče, což je vhodnější počínaje verzí Oracle 11g. Takže teď také znáte kung-fu.

Další informace o spouštěčích můžete najít na adrese:Složené spouštěče DML

Neváhejte a přidejte jakékoli komentáře.


  1. Riziko kolize UUID při použití různých algoritmů

  2. Co je efektivnější:Více tabulek MySQL nebo jedna velká tabulka?

  3. Jak vrátit výsledky dotazu jako seznam oddělený čárkami v MySQL

  4. Generování diagramu vztahu tabulky z existujícího schématu (SQL Server)