在Tracking changes in PostgreSQL上有帮助的文章之后,我得到了一个运行良好的触发函数,该函数可以跟踪与该触发函数关联的所有表的更改。 该函数以JSON的形式将整个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)
)
由于trigger-function非常通用,因此我想使用一种比较两个json列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;
答案 0 :(得分:0)
是的,您确实需要升级。 9.2中关于此的可能性相当有限。因此,以下答案假定最低为9.4,这是目前仍受支持的最低版本。
您可以使用json_each_text()
生成一组键值对,然后过滤具有相同键的不同值。
然后,您可以从那里构建一些JSON,例如,使用json_build_object()
每列一个JSON对象,并使用json_agg()
将它们聚合到JSON数组中。您没有指定所需的确切格式。所以这只是一个例子。您可能在那里提出了不同的想法。
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