PostgreSQL:如果只更新了一个特定列,则不要触发语句触发器

时间:2016-07-01 14:13:14

标签: postgresql

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

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();

1 个答案:

答案 0 :(得分:0)

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

中禁用thr触发器

我会重新设计这个。你可以使用一些“状态”'您的person_photo_date_func()将在其中放置'交易'要被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;