2016-07-01 17 views
0

人テーブルが更新されるたびにマテリアライズドビューをリフレッシュするPostgreSQLのpersonテーブルに文トリガがあります。カラムの1つは、PHPからアップロードされた画像を保存するためのbyteaです。この列はマテリアライズド・ビューにはありません。人物表に行トリガーがあり、イメージ列が更新されるたびにイメージアップロード日付列を更新します。行トリガーが起動すると、ステートメントトリガーが起動しないようにするにはどうすればよいですか?PostgreSQL:特定のカラムが1つしか更新されていない場合、ステートメントトリガを起動しない

create or replace function person_photo_date_func() returns trigger as $$ 
    begin 
     new.photo_utc := current_timestamp; 
     return new; 
    end; 
$$ language plpgsql; 

create trigger person_photo_date_tg 
    after update of photo on person 
    for each row execute procedure person_photo_date_func(); 

create or replace function refresh_mv() returns trigger as $$ 
    begin 
     refresh materialized view vm_csr; 
     return null; 
    end 
$$ language plpgsql security definer; 

create trigger refresh_mat_views_person 
    after insert or update or delete or truncate 
    on person for each statement 
    execute procedure refresh_mv(); 
+0

現在のトランザクションのアクティブなクエリは、次のように取得できます。フローまたは問題を理解していません。 \t [** How-to-Ask **](http://stackoverflow.com/help/how-to-ask) \t \t [**スタート**] http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/)質問品質を向上させ、より良い回答を得る方法を学ぶことができます。 –

+0

@JuanCarlosOropeza問題は非常に具体的ですが、正しく尋ねられます。私は彼の問題を抱えています。 –

+0

@Andy私は解決策を提供しようとしましたが、わかりましたが、複雑になっています。可能であれば、リフレッシュ・マテリアライズド・ビューの呼び出しをDBロジックの代わりにアプリ・ロジックに移動します。また、同じステートメントでマット・ビューと写真に存在する人物データを更新することも可能ですか?つまり、UPDATE person SET photo = '...'、location = '...'?そうであれば、あなたのロジックはマット・ビューのリフレッシュをスキップします。 DB上で更新を行うアプリケーションが1つしかない場合は、更新された内容といつ更新されたかを把握しているときに、マット・ビューの更新をアプリケーション・ロジックに呼び出すようにします。 –

答えて

0

これを参照してください、誰かが私はこれを再設計しまうストアドプロシージャhttps://dba.stackexchange.com/questions/48402/disabling-triggers-in-stored-procedures

からTHRトリガーを無効にするには、同じことを試みました。 person_photo_date_func()がrefresh_mv()によってスキップされる 'transactions'を入れる 'status'テーブルを使用することができます。

create table skip_refresh_mv (id serial primary key, xid integer); 

create or replace function person_photo_date_func() returns trigger as $$ 
    begin 
     new.photo_utc := current_timestamp; 
     INSERT INTO skip_refresh_mv (xid) SELECT txid_current(); 
     return new; 
    end; 
$$ language plpgsql; 

create or replace function refresh_mv() returns trigger as $$ 
    begin 
     IF NOT EXISTS (SELECT 1 FROM skip_refresh_mv WHERE xid = txid_current()) THEN 
     refresh materialized view vm_csr; 
     END IF;   
     return null; 
    end 
$$ language plpgsql security definer; 

しかし、それはあなたがまたskip_refresh_mvからクリーンアップ古いレコードに必要なので、テーブルをskip_refresh_mvと古いレコードの定期クリーンアップを行うには、いくつかのタイムスタンプ列を追加するトランザクションごと

を1文を想定しています。

トランザクションごとにこのようなステートメントが1つしかない場合は、存在を確認した後にrefresh_mv()の中からレコードをクリーンアップすることもできます。

P.S.私はpg_stat_activityを使うと文ごとにそれを行う必要があります。

select * from pg_stat_activity where state = 'active' and backend_xid = txid_current()::integer; 
+0

トリガは名前順(アルファベット順)で起動されますが、起動時に行トリガと文トリガを区別しているわけではありません。トリガーが現在の名前の正しい順序で起動すると仮定できますか? – Andy

+0

@Andyここにあるドキュメントに関する情報は、https://www.postgresql.org/docs/9.2/static/trigger-definitionにあります。htmlこのテキストを見てください:この段落では、「文レベルのBEFOREトリガは文が何かを開始する前に自然に発生しますが、文レベルのAFTERトリガは文の最後で起動します。行レベルのAFTERトリガーがステートメントの終わり(ただし、ステートメントレベルのAFTERトリガーの前)で起動している間に、特定の行が操作される直前.... " –

+0

トリガーの順序を最初にキャッチしませんでした。私はおそらく早すぎるだろう。情報をありがとう、それはまっすぐ前方に見える。私は、アプリケーションのデータベースの整合性ロジックに嫌悪感を持っています。私はSQLが使用されないという保証はないので、私はできる限りデータベースロジックを好む。特にアプリケーションがまだ完了していないので、データベースがきれいに保たれていることを確認する必要があります。 PostgreSQLはOracleのようなパッケージを持っていないので、漂遊テーブルは、あるトリガから別のトリガにヒントを渡す次善の方法のように聞こえます。他のところから読むと、私はリフレッシュを記録するためにテーブルが必要なように思えます。 – Andy

関連する問題