web-dev-qa-db-ja.com

PostgreSQLトリガーが別のトリガーによって起動されないようにするにはどうすればよいですか?

1つのテーブルに2つのトリガーがあります。 1つはINSERTで機能します。

_CREATE TRIGGER "get_user_name"
AFTER INSERT ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "add_info"();
_

これにより、テーブルの一部の値が更新されます。
そしてUPDATEの1つ(履歴テーブルを埋めるため):

_CREATE TRIGGER "set_history"
BEFORE UPDATE ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "gener_history"();
_

問題は、テーブルに新しい行を挿入すると、プロシージャ"add_info"()が更新を行うため、2番目のトリガーが起動し、エラーで終了することです。

_ERROR:  record "new" has no field "field1"
_

どうすればこれを回避できますか?

7
dd_a

(トリガーロジックの明らかなエラーは別です。)
Postgres9.2以降では、関数 pg_trigger_depth() トリガー @ Akashについてはすでに述べています トリガー自体の条件内 (トリガー関数の本体ではなく)、別のトリガーから呼び出されたときにトリガー関数が実行されないようにする(それ自体を含む-ループも防止する)。
これは通常、パフォーマンスが高く、シンプルでクリーンです。

CREATE TRIGGER set_history
BEFORE UPDATE ON field_data
FOR EACH ROW 
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE gener_history();

pg_trigger_depth() < 1は、トリガー関数に入る前に評価されます。したがって、最初の呼び出しでは0と評価されます。別のトリガーから呼び出された場合、値は高くなり、トリガー関数は実行されません。

12

挿入トリガー内から呼び出されたときに更新トリガーを実行したくない場合は、深度を返すpg_trigger_depth()の条件でステートメントを囲むことができます別のトリガーから直接/間接的にトリガーを実行している場合、これは0にはなりません

したがって、関数gener_history()内で、次のようなことができます

IF pg_trigger_depth() = 1 THEN
.. your statements..
END IF;

次に別の例を示します。 http://www.depesz.com/2012/02/01/waiting-for-9-2-trigger-depth/

4
Akash

提案#1

アプリからAFTER INSERTトリガーを削除してadd_infoを呼び出します

提案#2

AFTER INSERTトリガーをBEFORE INSERTに変更します

1
RolandoMySQLDBA