Postgresql:仅在数据发生变化时,仅在更新FOR FOR NOACH STATEMENT时运行触发器

时间:2015-08-25 17:18:50

标签: postgresql triggers publish-subscribe

在Postgresql中我可以有两种触发器:FOR EACH ROW和FOR EACH STATEMENT。如果我执行FOR EACH ROW触发器,我可以添加类似OLD.* != NEW.*的WHERE子句,因此只有在实际发生了某些变化时它才会触发。有没有办法用STATEMENT级触发器做类似的事情?我知道我不能做同样的事情,因为OLD和NEW都不可用,但我想也许有办法检查我的函数本身或类似内容中更改的行数。 / p>

用法案例:我正在使用postgresql NOTIFY系统在数据发生变化时通知我的应用。理想情况下,每当一个或更多记录发生更改时,应用程序就会收到一条通知,如果数据保持不变(即使运行了UPDATE),也不会得到通知。对于每个语句的基本AFTER UPDATE触发器,每次更新语句运行时我都会收到通知 - 即使它实际上没有更改任何内容。

1 个答案:

答案 0 :(得分:2)

您应该创建两个触发器:before update for each rowafter update for each statement

第一个触发器检查表是否正在更新,如果是,则设置标志。

第二个触发器检查标志并执行notify(如果已设置)。

您可以使用自定义配置参数作为标记(例如flags.the_table)。 解决方案简单而安全,因为参数在当前会话中是本地的。

create or replace function before_each_row_on_the_table()
returns trigger language plpgsql
as $$
begin
    if new <> old then
        set flags.the_table to 'on';
    end if;
    return new;
end $$;

create or replace function after_each_statement_on_the_table()
returns trigger language plpgsql
as $$
begin
    if (select current_setting('flags.the_table')) = 'on' then
        notify your_channel, 'the_table was updated';
        set flags.the_table to 'off';
    end if;
    return null;
exception
    when undefined_object then
        -- occurs when flags.the_table was not defined
        return null;
end $$;

create trigger before_each_row_on_the_table
before update on the_table
for each row execute procedure before_each_row_on_the_table();

create trigger after_each_statement_on_the_table
after update on the_table
for each statement execute procedure after_each_statement_on_the_table();