sql >> データベース >  >> RDS >> Oracle

変異テーブルの回避策としてのOracle

    Oracleの変異トリガーエラーは、トリガーがトリガーを所有するテーブルを参照している場合に発生し、「ORA-04091:テーブル名が変異しています。トリガー/関数に表示されない可能性があります」というメッセージが表示されます。

    既存の回避策を見てみましょう。

    最初のものは、パッケージを通して、古くて効果的であるように見えますが、それを準備して実行するのに多くの時間がかかります。 2つ目は単純で、複合トリガーを使用して実行されます。

    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;

    スプリンターがネズミから先生に変身するとき、画家は自動的に忍者に変わる必要があります。このトリガーは適しているようです:

    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表)、または複合トリガーのすべてのセクションでグローバルな変数のいずれかを使用できます。これは、バージョンOracle11g以降で使用することをお勧めします。だから、今あなたはカンフーも知っています。

    トリガーに関する追加情報は、Compound DML Triggers

    にあります。

    コメントを追加してください。


    1. SQL ServerのTRIM、LTRIM、およびRTRIM関数

    2. 日付範囲の重複チェック制約

    3. 1つのステートメントで複数の(3+)テーブルを結合する方法

    4. ORACLE SQL*Plusチュートリアル