检测postgres更新触发器中的列更改

时间:2014-05-21 16:08:54

标签: sql postgresql plpgsql

我有一个postgres数据库,其中包含几个我想要查看更新的表格,如果有任何更新,我想要点击“嘿,改变了一些”更新。这适用于基本情况,但现在是时候改进了。

CREATE FUNCTION notify_update() RETURNS trigger AS $notifyfunction$
BEGIN
  PERFORM pg_notify('update_watchers',
    $${"event":"update", "type": "$$ || TG_TABLE_NAME || $$", "payload": {"id": $$ || new.id || $$}}$$);
  RETURN new;
END;
$notifyfunction$ LANGUAGE plpgsql;

工作得很好。我把它像这样附在桌子上:

CREATE TRIGGER document_update_body
AFTER UPDATE ON documents
FOR EACH ROW EXECUTE PROCEDURE notify_update();

(作为一个侧面问题:如果json.stringify我的触发结果比触发器功能中的mess'o' $$更好/更简单,请告诉我。平衡引号并不好玩)

我想要做的是在pg_notify调用中附加已更改的列的列表。除了迭代表中的列并检查NEW.col是否与OLD.col不同之外,它不像似乎就像有任何简单的方法来做到这一点。执行此操作的不好方法是在我的通知过程中对列名进行硬编码(脆弱,如果我更改模式则更新另一件事等)。

我也非常喜欢编写plpgsql,所以我不确定在哪里寻求帮助。理想情况下(如果没有我在文档中没有看到的updated_columns块变量),有一种方法可以在通知块中获取表的模式,而不会导致过于严重的性能开销(因为这些表将更新为公平的)。

3 个答案:

答案 0 :(得分:6)

阅读hstore扩展程序。特别是您可以从一行创建一个hstore,这意味着您可以执行以下操作:

changes := hstore(NEW) - hstore(OLD);
...pg_notify(... changes::text ...)

这比您想要的信息略多(包括新值)。如果您只想要密钥,可以使用akeys(changed)

答案 1 :(得分:1)

http://www.postgresql.org/docs/9.3/static/plpython-trigger.html

TD["table_name"]

我完全使用相同类型的通知,我遍历所有列,如下所示:

    for k in TD["new"]:
        if TD["old"][k] != TD["new"][k]:
            changed.append(k)

changed.append(k)构建我的通知字符串。在其他地方我做一个监听,然后将结果从pub / sub广播到web套接字客户端。

-g

答案 2 :(得分:0)

另一种方法是利用PostgreSQL最新版本中的JSON / JSONB函数。它的优点是可以处理可转换为JSON对象(行或任何其他结构化数据)的任何内容,甚至不需要知道记录类型。

请参阅我的原始StackOverflow post和适当的示例。