ELSE
ブランチは根本的に単純化できます。しかし、さらにいくつかのことが非効率的/不正確/危険です:
CREATE OR REPLACE FUNCTION sample_trigger_func()
RETURNS TRIGGER AS
$func$
BEGIN
IF TG_OP = 'DELETE' THEN
RAISE INFO 'OLD: %', OLD.name;
EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
, ARRAY[left(TG_OP, 1), now()::text]);
RETURN OLD;
ELSE -- insert, update
NEW.mod_op := left(TG_OP, 1);
NEW.mod_datetime := now();
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
-
ELSE
内 ブランチはNEW
に割り当てるだけです 直接。より動的なSQLは必要ありません。同じトリガーを再度起動すると、無限ループが発生します。それが主なエラーです。 -
RETURN NEW;
IF
の外 コンストラクトはDELETE
のトリガー関数を壊します 、NEW
以降 DELETEには割り当てられていません。 -
重要な機能は、
hstore
の使用です。 およびhstore演算子#=
よく知られている行タイプの2つの選択されたフィールドを動的に変更します -それは不明です コードを書いている時点で。このようにして、元のOLD
を改ざんすることはありません。 値。これは、イベントのチェーンの下にさらにトリガーがある場合、驚くべき副作用をもたらす可能性があります。OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
追加モジュール
hstore
インストールする必要があります。詳細:hstore(text []、text [])を使用するコード>
hstore
を構築するためのバリアント その場で複数のフィールドを持つ値。 -
plpgsqlの代入演算子は
:=
です。 : -
列名
mod_datetime
を使用したことに注意してください 誤解を招くmod_date
の代わりに 、列は明らかにタイムスタンプ
であるためdate
ではありません 。
私はそれに取り組んでいる間、他のいくつかの改善を追加しました。そして、トリガー自体は次のようになります。
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();