[英]Postgresql Trigger log only changes of affected columns
根据一篇关于在 PostgreSQL 中跟踪更改的有用文章,我得到了一个运行良好的触发器函数,它跟踪与该触发器函数关联的所有表的更改。 该函数将整个 OLD 和 NEW 行内容存储为 JSON,这很好,但是对于很多列,很难大致了解真正的变化。
我正在寻找一种方法来仅存储 NEW 和 OLD 值已更改的列的内容。 因此,我添加了一个新列“更改”。
这是存储历史记录的表:
CREATE TABLE public.t_history
(
id integer serial,
tstamptz timestamp with time zone DEFAULT now(),
schemaname text,
tabname text,
operation text,
who text DEFAULT "current_user"(),
changes text,
new_val json,
old_val json,
CONSTRAINT pk_t_history PRIMARY KEY (id)
)
由于触发器函数非常通用,我想使用一种方法来比较两个 json-colums new_val 和 old_val,或者有一种方法使用 foreach 循环来查看每列而不指定硬编码列名。 结果,真正的更改应该存储在“更改”列中。
这是触发器函数的样子:
REATE OR REPLACE FUNCTION public.change_trigger()
RETURNS trigger AS
$BODY$
BEGIN
IF TG_OP = 'INSERT'
THEN
INSERT INTO public.t_history (tabname, schemaname, operation, new_val)
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW));
RETURN NEW;
ELSIF TG_OP = 'UPDATE'
THEN
INSERT INTO public.t_history (tabname, schemaname, operation, new_val, old_val)
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,
row_to_json(NEW), row_to_json(OLD));
RETURN NEW;
ELSIF TG_OP = 'DELETE'
THEN
INSERT INTO public.t_history (tabname, schemaname, operation, old_val)
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD));
RETURN OLD;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER
COST 100;
是的,你真的需要升级。 9.2 中关于此的可能性相当有限。 因此,以下答案假定最低为 9.4,这是目前仍受支持的最低版本。
您可以使用json_each_text()
生成一组键值对,然后过滤具有相同键的不同值。
然后可以从那里使用建立一些JSON,为每列例如一个JSON对象json_build_object()
和使用它们聚集在一个JSON阵列json_agg()
您没有指定所需的确切格式。 所以这只是一个例子。 您可能会在那里提出不同的想法。
SELECT json_agg(json_build_object('column',
old2.key,
'old',
old2.value,
'new',
new2.value))
FROM (VALUES (1,
2,
3)) old(i,
j,
k)
CROSS JOIN (VALUES (1,
3,
4)) new(i,
j,
k)
CROSS JOIN LATERAL json_each_text(row_to_json(old)) old2
CROSS JOIN LATERAL json_each_text(row_to_json(new)) new2
WHERE old2.key = new2.key
AND old2.value <> new2.value;
注意: VALUES
x VALUES
交叉连接仅用于演示,因此我有一个new
和一个old
,毕竟我不在触发器中。 当然,在触发器中,您已经有了new
和old
,可以跳过它并使用FROM
子句,例如:
FROM json_each_text(row_to_json(old)) old2
CROSS JOIN json_each_text(row_to_json(new)) new2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.