Postgresql:运行 仅当数据更改时才在更新每个语句后触发

Postgresql: run trigger AFTER update FOR EACH STATEMENT ONLY if data changed

在 Postgresql 中,我可以有两种触发器:FOR EACH ROW 和 FOR EACH STATEMENT。如果我执行 FOR EACH ROW 触发器,我可以添加一个 WHERE 子句,例如 OLD.* != NEW.* 这样它只会在实际发生更改时触发。有什么方法可以用 STATEMENT 级别的触发器做类似的事情吗?我知道我不能做同样的事情,因为 OLD 和 NEW 不可用,但我在想也许有一种方法可以检查从我的函数本身或类似函数中更改的行数。

用例:我正在使用 postgresql NOTIFY 系统在数据更改时通知我的应用程序。理想情况下,应用程序会在每次 或更多 记录更改时收到一个通知,如果数据保持不变(即使更新是 运行),则根本不会收到通知.使用基本的 AFTER UPDATE FOR EACH STATEMENT 触发器,每次更新语句 运行s 时我都会收到通知 - 即使它实际上没有改变任何东西。

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

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

第二个触发器检查标志并执行 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();