使用 Postgres 触发器仅记录修改字段的 JSON
Use a Postgres trigger to record the JSON of only the modified fields
有没有办法获取唯一修改字段的 JSON?
现在我使用以下触发器,但整行都打印在更改日志中。
示例表:
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 后,更改日志如下:
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"}
------------------------------------------------------------------
您的触发函数无法正常工作,它在插入一行时产生错误:
ERROR: record "old" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
INSERT
、UPDATE
、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;
有没有办法获取唯一修改字段的 JSON?
现在我使用以下触发器,但整行都打印在更改日志中。
示例表:
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 后,更改日志如下:
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"}
------------------------------------------------------------------
您的触发函数无法正常工作,它在插入一行时产生错误:
ERROR: record "old" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
INSERT
、UPDATE
、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;