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

pfo*_*oti 8 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;
Run Code Online (Sandbox Code Playgroud)

工作得很好.我把它附在桌子上,如下:

CREATE TRIGGER document_update_body
AFTER UPDATE ON documents
FOR EACH ROW EXECUTE PROCEDURE notify_update();
Run Code Online (Sandbox Code Playgroud)

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

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

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

Ric*_*ton 8

阅读hstore扩展.特别是你可以从一行创建一个hstore,这意味着你可以这样做:

changes := hstore(NEW) - hstore(OLD);
...pg_notify(... changes::text ...)
Run Code Online (Sandbox Code Playgroud)

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