web-dev-qa-db-ja.com

列または列または列Sの更新時にトリガーを起動します

特定の1つの列の更新時にのみトリガーを起動するコードがあります。トリガーは、postgresの「通知」イベントを発生させる関数を起動するために使用されます。このイベントは、私がリッスンしていて、新しく入力された詳細をテストおよび検証する必要があります。 account_detailsテーブルには、アカウントの検証を必要としない変更可能な値が多数あるため、AFTER UPDATEのみのトリガー(whenなし)は適切ではありません。

    CREATE TRIGGER trigger_update_account_details
    AFTER UPDATE ON account_details
    FOR EACH ROW
    WHEN (OLD.email IS DISTINCT FROM NEW.email) 
    EXECUTE PROCEDURE notify_insert_account_details();

しかし、私は多くの列の1つが変更された場合にトリガーを起動したいと思います。

WHEN (OLD.email IS DISTINCT FROM NEW.email OR 
OLD.username IS DISTINCT FROM NEW.username OR 
OLD.password IS DISTINCT FROM NEW.password) 

ただし、ORはトリガーに有効なキーワードではありません。ORの代わりに使用するキーワードを検索しようとしても、言葉の性質OR :-(

18
Martin

これは誤解です。トリガー定義の WHEN句にはboolean が必要であり、その中でOR演算子を使用できます。これは機能するはずです(すべての列が実際にテーブルaccount_detailsに存在する場合)。私自身も同様のトリガーを使用しています:

CREATE TRIGGER trigger_update_account_details
AFTER UPDATE ON account_details
FOR EACH ROW
WHEN (OLD.email    IS DISTINCT FROM NEW.email
   OR OLD.username IS DISTINCT FROM NEW.username
   OR OLD.password IS DISTINCT FROM NEW.password) 
EXECUTE PROCEDURE notify_insert_account_details();

式の評価にはわずかなコストがかかりますが、これはおそらく他の方法より信頼性が高いです。

CREATE TRIGGER ... AFTER UPDATE OF email, username, password ...

なぜなら、 ドキュメントごと

列固有のトリガー(UPDATE OFcolumn_nameを使用して定義されたトリガー)構文)は、その列のいずれかがUPDATEコマンドのSETリストにターゲットとしてリストされているときに起動します。 BEFORE UPDATEトリガーによって行の内容に加えられた変更は考慮されないため、トリガーが起動されていなくても、列の値が変更される可能性があります。逆に、列の値が変更されていなくても、UPDATE ... SET x = x ...などのコマンドは列xでトリガーを起動します。

ROW タイプ構文は多くの列をチェックするために短くなっています(同じことをしています):

CREATE TRIGGER trigger_update_account_details
AFTER UPDATE ON account_details
FOR EACH ROW
WHEN ((OLD.email, OLD.username, OLD.password, ...)
       IS DISTINCT FROM
      (NEW.email, NEW.username, NEW.password, ...))
EXECUTE PROCEDURE notify_insert_account_details();

または、行のevery表示されているユーザー列を確認するには:

...
WHEN (OLD IS DISTINCT FROM NEW)
...
30

WHEN句は必要ないと思います。問題の列をUPDATE句で指定できます。

CREATE TRIGGER trigger_update_account_details
    AFTER UPDATE OF email, username, password ON account_details
    FOR EACH ROW
    EXECUTE PROCEDURE notify_insert_account_details();

上記の解決策は私にとって適切に機能しませんでした。もう一度ドキュメントを読んだ後。注意すべきことがいくつか見つかりました。 BEFORE UPDATE ON-AFTER UPDATE ONトリガーの実行方法は異なります。私の手順では、更新された値でNEWレコードを返していました。 AFTERトリガーおよびBEFOREトリガーでは機能せず、WHEN句内のORステートメントを中括弧で囲む必要がありました。

CREATE TRIGGER check_update
BEFORE UPDATE ON some_table
FOR EACH ROW
WHEN ((OLD.colum_name_1 IS DISTINCT FROM NEW.colum_name_1) OR (OLD.colum_name_2 IS DISTINCT FROM NEW.colum_name_2))
EXECUTE PROCEDURE update_updated_at_column();

そして手順

CREATE OR REPLACE FUNCTION update_updated_at_column()
  RETURNS TRIGGER AS $$
  BEGIN
      NEW.updated_at = now();
      RETURN NEW;
  END;
  $$ language 'plpgsql';
0
Sandeep PC