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

ibr*_*ter 4 postgresql triggers publish-subscribe

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

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

kli*_*lin 6

您应该创建两个触发器: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 current_setting('flags.the_table', true) = 'on' then
        notify your_channel, 'the_table was updated';
        set flags.the_table to 'off';
    end if;
    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();
Run Code Online (Sandbox Code Playgroud)

current_setting()Postgres 9.6 或更高版本中提供了带有两个参数的函数。