Oracle
 sql >> база данни >  >> RDS >> Oracle

Oracle като решение за мутиращи таблици

Грешката на мутиращия тригер на Oracle възниква, когато тригер препраща към таблицата, която притежава тригера, което води до съобщението „ORA-04091:името на таблицата се променя, тригерът/функцията може да не го вижда“.

Нека да разгледаме съществуващите решения.

Първият, чрез пакета, е древен и изглежда ефективен, но отнема много време, за да го подготвите и стартирате. Вторият е прост и се изпълнява с помощта на сложни тригери.

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;

Когато Splinter мутира от плъх в сенсей, художниците ще трябва автоматично да се превърнат в нинджи. Този тригер изглежда е подходящ:

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;

Въпреки това, когато актуализирате записа:

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

Възниква следната грешка:

ORA-04091:таблица SCOTT.TURTLES мутира, тригерът/функцията може да не я види

Нека изтрием този тригер:

drop trigger tr_turtles_bue;

Метод 1: Използване на пакета и тригера на ниво инструкция.

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

Метод 2: Използване на съставни DML тригери (достъпно, като се започне с 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;

Нека опитаме следното:

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

Дори ако сте се сблъскали с по-сложен случай на мутация, можете да използвате гореспоменатата идея като заобиколно решение. В тригера на ниво инструкция, за разлика от тригера на ниво ред, не възниква мутация. Можете да използвате или променливи (тагове, ключалки, PL SQL таблици) в допълнителен пакет, или променливи, които са глобални за всички секции на съставния тригер, което е за предпочитане, започвайки с версията Oracle 11g. И така, вече знаете и кунг-фу.

Можете да намерите допълнителна информация за тригерите на:Съставни DML тригери

Чувствайте се свободни да добавяте коментари.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да избегнем заместването на променливи в Oracle SQL Developer с "тринидад и тобаго"

  2. НАЧАЛО - КРАЙ блок атомарни транзакции в PL/SQL

  3. C#:Предайте дефиниран от потребителя тип към съхранена процедура на Oracle

  4. Zip с помощта на Oracle Stored Procedure

  5. PLS-00428:в този оператор SELECT се очаква клауза INTO