我们需要将记录历史记录存储在PostgreSQL中,以便在将记录插入主表或在主表中更新记录(例如: pets
)时,该记录会自动备份到历史记录中表格( pets_history
)。
理想情况下,我们需要基于主表的架构生成历史表,而无需任何人工干预。
INSERT INTO pets(name, species) VALUES ('Meowth', 'Cat')
pets:
+---+------------+-------------+
|id | name | species |
+---+------------+-------------+
| 1 | Meowth | Cat |
+---+------------+-------------+
Trigger
应该自动将记录插入 pets_history
:
pets_history:
+----+--------+-----------+---------+
| id | ref_id | name | species |
+----+--------+-----------+---------+
| 1 | 1 | Meowth | Cat |
+----+--------+-----------+---------+
对宠物进行更新后,我的猫的名字从Meowth
更改为Persian
。例如:
UPDATE pets SET name = 'Persian' WHERE id = 1;
pets:
+---+------------+-------------+
|id | name | species |
+---+------------+-------------+
| 1 | Persian | Cat |
+---+------------+-------------+
我想结束以下内容...
pets_history:
+----+--------+-----------+---------+
| id | ref_id | name | species |
+----+--------+-----------+---------+
| 1 | 1 | Meowth | Cat |
| 2 | 1 | Persian | Cat |
+----+--------+-----------+---------+
稍后将另一列/字段添加到pets
表时,例如: color
pets:
+---+--------+---------+-------+
|id | name | species | color |
+---+--------+---------+-------+
| 1 | Meowth | Cat | cream |
+---+--------+---------+-------+
我们希望这会自动反映在pets_history
表中:
pets_history:
+----+--------+---------+---------+-------+
| id | ref_id | name | species | color |
+----+--------+---------+---------+-------+
| 1 | 1 | Meowth | Cat | null |
| 2 | 1 | Persian | Cat | null |
| 3 | 1 | Persian | Cat | cream |
+----+--------+---------+---------+-------+
如果有人知道在PostgreSQL中以其他方式进行此操作的方式,否则请分享。
我们看了这个问题/答案Implementing history of PostgreSQL table,它部分解决了难题,但它不会自动创建_history
表。
答案 0 :(得分:0)
您可以使用 to_jsonb 将整行作为 JSON 对象保存在历史表中。在这种情况下,您不需要关心在历史表中添加新列,因为值的键将是列名。
宠物桌
CREATE TABLE public.pets
(
id serial NOT NULL,
name text,
species text,
PRIMARY KEY (id)
);
宠物历史表
CREATE TABLE public.h_pets
(
id serial NOT NULL,
target_row_id integer NOT NULL,
executed_operation integer NOT NULL,
operation_executed_at timestamp without time zone NOT NULL DEFAULT now(),
data_after_executed_operation jsonb,
PRIMARY KEY (id)
);
向历史表中添加行的函数
CREATE OR REPLACE FUNCTION public.on_content_change()
RETURNS trigger
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
target_history_table TEXT;
BEGIN
target_history_table := TG_ARGV[0];
IF TG_OP = 'INSERT'
THEN
EXECUTE
format(
'INSERT INTO %I (target_row_id, executed_operation, data_after_executed_operation) VALUES ($1.id, 0, to_jsonb($1))',
target_history_table
)
USING NEW;
RETURN NEW;
ELSIF TG_OP = 'UPDATE'
THEN
EXECUTE
format(
'INSERT INTO %I (target_row_id, executed_operation, data_after_executed_operation) VALUES ($1.id, 1, to_jsonb($1))',
target_history_table
)
USING NEW;
RETURN NEW;
ELSIF TG_OP = 'DELETE'
THEN
EXECUTE
format(
'INSERT INTO %I (target_row_id, executed_operation) VALUES ($1.id, 2)',
target_history_table
)
USING OLD;
RETURN OLD;
END IF;
END;
$BODY$;
和宠物表的触发器
CREATE TRIGGER pets_history_trigger
BEFORE INSERT OR DELETE OR UPDATE
ON public.pets
FOR EACH ROW
EXECUTE PROCEDURE public.on_content_change('h_pets');