2016-07-01 73 views
0

我在PostgreSQL的人员表上有一个语句触发器,用于在更新人员表时刷新物化视图。其中一列是用于存储从PHP上传的图像的bytea。此列不在物化视图中。每当更新图像列时,人员表上都有一个行触发器来更新图像上传日期列。如果行触发器触发,如何防止触发语句触发器?PostgreSQL:如果只更新一个特定列,不要触发语句触发器

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请阅读[**如何提问**](http://stackoverflow.com/help/how-to-ask) \t \t这里是[** START **]( http://spaghettidba.com/2015/04/24/how-to-post-at-sql-question-on-a-public-forum/)了解如何提高您的问题质量并获得更好的答案。 –

+0

@JuanCarlosOropeza问题是非常具体的,但它的要求正确。我确实遇到了他的问题。 –

+0

@我试着提供解决方案,但正如你所看到的那样,它变得越来越复杂。如果可能的话,我会将刷新物化视图的调用移动到应用程序逻辑而不是数据库逻辑。另外,用户是否有可能用相同的语句更新席位视图和照片中存在的某些人数据,即UPDATE person SET photo ='...',location ='...'?如果是这样,那么你的逻辑将跳过垫视图的刷新。如果您只有一个应用程序在数据库上执行更新,那么当您更好地确定更新内容和时间时,我会将mat视图刷新调用应用程序逻辑。 –

回答

0

看到这,有人尝试过同样,从存储过程https://dba.stackexchange.com/questions/48402/disabling-triggers-in-stored-procedures

我会重新设计这个禁用THR触发。你可以使用一些'status'表,其中你的person_photo_date_func()将放置'transactions'被refresh_mv()忽略。

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表和做旧记录日常清理。

如果每笔交易最多只有一条这样的声明,那么您也可以在检查存在之后清除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触发器在语句的最后触发......行级BEFORE触发器触发紧接在特定行被操作之前,而行级别的AFTER触发器在语句结束时触发(但在任何语句级别的AFTER触发器之前)......“ –

+0

我第一次没有捕获触发器命令。我可能会太快。感谢信息,现在看起来很直接。我对应用中的数据库组成逻辑产生了反感。我没有保证SQL不会被使用,所以我更喜欢数据库逻辑。特别是因为该应用还没有完成,我需要确保数据库保持清洁。由于PostgreSQL没有像Oracle这样的软件包,所以流浪表听起来像是将提示从一个触发器传递到另一个触发器的下一个最佳方式。从别处读取它听起来像我会需要一张表来记录刷新。 – Andy