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
にあります。コメントを追加してください。