使用Postgres触发器记录仅修改字段的JSON

发布于 2025-01-29 08:53:39 字数 1899 浏览 4 评论 0原文

有没有办法获得唯一修改的字段的JSON?

现在,我使用以下触发器,但整个行都印在ChangElog中。

示例表:

TABLE tbl_changelog (
  tbl    TEXT,
  op   TEXT,
  new     JSON,
  old     JSON
);

TABLE tbl_items (
  f1    TEXT,
  f2    TEXT
);

触发器:

CREATE OR REPLACE FUNCTION changelog_procedure() RETURNS trigger AS $$
BEGIN
INSERT INTO tbl_changelog(tbl, op, new, old)
VALUES (TG_TABLE_NAME, TG_OP, row_to_json(NEW), row_to_json(OLD));
RETURN NULL;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER changelog_items
AFTER INSERT OR UPDATE OR DELETE ON tbl_items
FOR EACH ROW EXECUTE PROCEDURE changelog_procedure();

插入和上传的F2和F1后,ChangElog如下:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "aa", f2: "cc"} | {f1: "aa", f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd", f2: "cc"} | {f1: "aa", f2: "cc"}
------------------------------------------------------------------

我只想记录更改,即:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f2: "cc"}           | {f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd"}           | {f1: "aa"}
------------------------------------------------------------------

Is there a way to get the JSON of the only modified fields?

Now I use the following trigger but the entire line is printed in the changelog.

Example tables:

TABLE tbl_changelog (
  tbl    TEXT,
  op   TEXT,
  new     JSON,
  old     JSON
);

TABLE tbl_items (
  f1    TEXT,
  f2    TEXT
);

Trigger:

CREATE OR REPLACE FUNCTION changelog_procedure() RETURNS trigger AS $
BEGIN
INSERT INTO tbl_changelog(tbl, op, new, old)
VALUES (TG_TABLE_NAME, TG_OP, row_to_json(NEW), row_to_json(OLD));
RETURN NULL;
END;
$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER changelog_items
AFTER INSERT OR UPDATE OR DELETE ON tbl_items
FOR EACH ROW EXECUTE PROCEDURE changelog_procedure();

After inserting and uploaded f2 and f1 the changelog is the following:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "aa", f2: "cc"} | {f1: "aa", f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd", f2: "cc"} | {f1: "aa", f2: "cc"}
------------------------------------------------------------------

I would like to record only the changes, that is:

tbl_changelog
------------------------------------------------------------------
 tbl      |   op    | new                  |     old
------------------------------------------------------------------
tbl_items | INSERT  | {f1: "aa", f2: "bb"} | 
------------------------------------------------------------------
tbl_items | UPDATE  | {f2: "cc"}           | {f2: "bb"}
------------------------------------------------------------------
tbl_items | UPDATE  | {f1: "dd"}           | {f1: "aa"}
------------------------------------------------------------------

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

桃扇骨 2025-02-05 08:53:39

您的触发功能无法正常工作,它在插入一行时会产生错误:

错误:记录“旧”尚未分配

细节:尚未分配的记录的元组结构不确定。

您应该分别处理insert的三种情况 和delete单独处理:

create or replace function changelog_procedure() 
returns trigger as $
declare
    json_new jsonb;
    json_old jsonb;
begin
    if tg_op = 'INSERT' then
        json_new:= to_jsonb(new);
    elsif tg_op = 'DELETE' then
        json_old:= to_jsonb(old);
    else
        select jsonb_object_agg(new_key, new_value), jsonb_object_agg(old_key, old_value)
        into json_new, json_old
        from jsonb_each(to_jsonb(new)) as n(new_key, new_value)
        join jsonb_each(to_jsonb(old)) as o(old_key, old_value) 
        on new_key = old_key and new_value <> old_value;
    end if;
    insert into tbl_changelog(tbl, op, new, old)
    values (tg_table_name, tg_op, json_new, json_old);
    return null;
end;
$ language plpgsql;

Your trigger function cannot work well, it produces the error while inserting a row:

ERROR: record "old" is not assigned yet

DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.

You should treat the three cases of INSERT, UPDATE and DELETE separately:

create or replace function changelog_procedure() 
returns trigger as $
declare
    json_new jsonb;
    json_old jsonb;
begin
    if tg_op = 'INSERT' then
        json_new:= to_jsonb(new);
    elsif tg_op = 'DELETE' then
        json_old:= to_jsonb(old);
    else
        select jsonb_object_agg(new_key, new_value), jsonb_object_agg(old_key, old_value)
        into json_new, json_old
        from jsonb_each(to_jsonb(new)) as n(new_key, new_value)
        join jsonb_each(to_jsonb(old)) as o(old_key, old_value) 
        on new_key = old_key and new_value <> old_value;
    end if;
    insert into tbl_changelog(tbl, op, new, old)
    values (tg_table_name, tg_op, json_new, json_old);
    return null;
end;
$ language plpgsql;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文