A と B の 3 つのテーブルがあります。関係は、A は多くの B を持つことができるため、B はその列の 1 つとして A.id への参照を持っています。
Table A
|id|date|...
Table B
|id|A_id|...
テーブル A に Oracle トリガーを作成して、更新時に A_Mod テーブルを更新するようにしました。
このトリガーは
CREATE OR REPLACE TRIGGER TR_A_INSERT_UPDATE
AFTER INSERT OR UPDATE ON A
FOR EACH ROW
BEGIN
INSERT INTO A_Mod values(..., :new.date, ...)
END;
これはうまくいきます:)
私の問題は、テーブル B のトリガーを作成することです。
トリガーは次のとおりです。
CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE
AFTER INSERT OR UPDATE ON B
FOR EACH ROW
DECLARE
ts TIMESTAMP;
BEGIN
SELECT aa.date INTO ts FROM B bb
INNER JOIN A aa ON a.id = bb.A_id
WHERE bb.id = :new.id;
INSERT INTO A_Mod values(..., :new.date, ...)
END;
このトリガーは、テーブル B の更新された行の ID を読み取り、テーブル A の対応する行から日付を取得します。次に、それを A_Mod に挿入しようとします。
問題は、変異エラーが発生することです
Error report:
SQL Error: ORA-04091: table B is mutating, trigger/function may not see it
ORA-06512: at "TR_B_INSERT_UPDATE", line 5
ORA-04088: error during execution of trigger 'TR_B_INSERT_UPDATE'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
ドキュメントを見ると、FOR EACH ROW
行を削除し、行ごとではなくステートメントごとにトリガーを1回実行することで、このエラーを削除できます。残念ながら、私は ORM マッパーを使用しているため、更新がどのように行われるかを制御しません。更新が複数の行をカバーする場合があると思います。
ドキュメントには、一時テーブルの作成について何か書かれていますが、これがどのように役立つかわかりません。トリガー内に一時テーブルを作成し、この一時テーブルにトリガーを作成して A_Mod を更新し、トリガーが起動されたときにこの一時テーブルを更新し、その後すべてを削除する必要がありますか?
どんなヒントでも大歓迎です。
ありがとう