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