1

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 を更新し、トリガーが起動されたときにこの一時テーブルを更新し、その後すべてを削除する必要がありますか?

どんなヒントでも大歓迎です。

ありがとう

4

1 に答える 1

2

テーブルBをクエリするトリガーに理由がないようです。を使用しBて簡単にクエリできるはずですA:new.a_id

CREATE OR REPLACE TRIGGER TR_B_INSERT_UPDATE
  AFTER  INSERT OR UPDATE ON B
  FOR EACH ROW
DECLARE
   ts TIMESTAMP;
BEGIN
  SELECT a.date 
    INTO ts 
    FROM A a
   WHERE a.id = :new.a_id;

  INSERT INTO A_Mod values(..., :new.date, ...)
END;

ただし、データモデリングの観点からは、子テーブルのトリガーで親テーブルの情報をクエリしたり、親テーブルが書き込むのと同じ履歴テーブルにデータを挿入したりする必要があるかどうかが非常に心配です。これは、正規化の問題を示している可能性があります。

于 2012-10-24T11:50:24.660 に答える