在 postgresql 中为每个更新的行调用一个函数

Posted

技术标签:

【中文标题】在 postgresql 中为每个更新的行调用一个函数【英文标题】:Calling a function for each updated row in postgresql 【发布时间】:2015-08-03 08:13:50 【问题描述】:

我在 plpgsql 函数中有一个 sql UPDATE 语句。我现在想为每个更新的行调用 pg_notify 函数,但不确定我的解决方案是否是最好的。

我不知道UPDATE 语句本身的任何位置可以应用该函数。我认为在SET 部分是不可能的,如果我在WHERE 部分应用该函数,它会在检查时应用于每一行,而不仅仅是更新的行,对吗?

因此,我认为我可以将RETURNING 部分用于我的目的,并设计了这样的功能:

CREATE OR REPLACE FUNCTION function_name() RETURNS VOID AS $BODY$
BEGIN
    UPDATE table1
    SET a = TRUE
    FROM table2
    WHERE table1.b = table2.c
    AND <more conditions>
    RETURNING pg_notify('notification_name', table1.pk);
END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE;

不幸的是,这给了我一个错误,说我没有在任何地方使用或存储查询的返回值。因此,我尝试将 PERFORM 放在查询前面,但这似乎在语法上不正确。

在尝试了 PERFORM 的不同组合后,我的最终解决方案是:

CREATE OR REPLACE FUNCTION function_name() RETURNS VOID AS $BODY$
DECLARE
    dev_null INTEGER;
BEGIN
    WITH updated AS (
        UPDATE table1
        SET a = TRUE
        FROM table2
        WHERE table1.b = table2.c
        AND <more conditions>
        RETURNING pg_notify('notification_name', table1.pk)
    )
    SELECT 1 INTO dev_null;

END;
$BODY$ LANGUAGE 'plpgsql' VOLATILE;

这按预期工作,但我觉得应该有一个更好的解决方案,它不会暂时存储无用的结果并且不使用无用的变量。

感谢您的帮助。

** 编辑 1 **

从@pnorton 的回答中可以看出,在大多数情况下,触发器可以解决问题。但是,对我来说,它不适用,因为通知的接收者有时也会更新表格,我不想在这种情况下生成通知

【问题讨论】:

我不确定这是否安全。 为什么 PERFORM function_name() 看起来比 SELECT function_name() 更糟?.. 函数对表执行 UPDATE,为什么 SELECT UPDATE 比 PERFORM UPDATE 更好?.. @JakubKania:我也不确定,但我不需要通知来保证交易安全。接收者在对其进行任何操作之前检查该行是否存在。 @VaoTsun 我不确定你的意思。我真的不在乎它的外观,但我没有找到解决我的问题使用PERFORM @a_horse_with_no_name 我没有,但我猜它不起作用,因为FROM 子句中只允许使用表格 【参考方案1】:

“我在 plpgsql 函数中有一个 sql UPDATE 语句。我现在想 为每个更新的行调用 pg_notify 函数 "

好吧,我可能想使用触发器 Eg

    CREATE TABLE foobar (id serial primary key, name varchar);

CREATE OR REPLACE FUNCTION notify_trigger() RETURNS trigger AS $$
DECLARE
BEGIN
  PERFORM pg_notify('watch_tb_update', TG_TABLE_NAME || ',id,' || NEW.id );
  RETURN new;
END;
$$ LANGUAGE plpgsql;

CREATE  TRIGGER foobar_trigger AFTER INSERT ON foobar
FOR EACH ROW EXECUTE PROCEDURE notify_trigger();

LISTEN watch_tb_update;

INSERT into foobar(id, name) values(1,'test_name');

我已经测试过了,效果很好

【讨论】:

好主意。正如我所说,这实际上可以解决问题。然而,我没有说的是,信号的接收者有时也会插入或更新我不希望通知他的行。当然,我可以向接收器添加一个机制,检查它是否自己生成了通知,但我不希望这样做,因为它看起来过于复杂。

以上是关于在 postgresql 中为每个更新的行调用一个函数的主要内容,如果未能解决你的问题,请参考以下文章

在 Postgresql 中为每个被拒绝或接受的日期查找第一个 OPENED_DATE

postgresql函数-获取受更新查询影响的行数[重复]

PostgreSQL Upsert 使用系统列 XMIN、XMAX 等来区分插入和更新的行

有没有办法在聚合调用中不使用 ORDER BY 对 postgresql 自定义聚合中的行进行预排序?

如何在 Oracle Apex 5 中为每一行唯一地更新列?

在 spark scala 中为数据帧中的每个组采样不同数量的随机行