场景
我们需要在PostgreSQL中存储记录历史,以便当记录插入或更新主表(例如:pets
)时,它会自动备份到历史表(pets_history
)。
理想情况下,我们需要基于主表的模式生成历史表,而不需要任何人工干预。
INSERT INTO pets(name, species) VALUES ('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
表。
2条答案
按热度按时间e4yzc0pl1#
您可以使用to_jsonb将整行作为JSON对象保存在历史表中。在这种情况下,您不需要关心在历史表中添加新列,因为值的键将是列名。
宠物桌
字符串
宠物历史表
型
向历史表添加行的函数
型
和触发器的宠物表
型
n3h0vuf22#
根据您选择的DBMS,您可以自动执行此操作。
Postgres有两个结构可以帮助您:(1)事件触发器--触发DB级事件,如创建和更改表;(2)触发器函数--可以创建触发器并将其应用于表。
在高级别上,你可以这样做:
1.创建一个触发器函数
CreateHistoryTrigger
,它实现了在基表上插入和更新时触发的逻辑,并插入到相应的历史表中。您可以通过为基表名称、列名和其他选项创建参数来泛化这一点。调用时,此函数将动态设计一个触发器,并将其应用于命名表。1.创建一个事件触发器
ManageHistoryTables
来监视您感兴趣的更改,也就是说,假设您不希望每个表都有历史表,您可以通过模式、命名约定、要监视的特定表列表或任何适当的方式来过滤数据库事件。可能您希望至少监视CREATE TABLE
、ALTER TABLE
和DROP TABLE
。1.对于
CREATE TABLE
或ALTER TABLE
,检查系统表以查看与基表对应的历史表是否存在。如果不存在,则通过从查询系统表发现的基表的列属性构建create或alter table命令并运行该命令来创建它。1.对于
ALTER TABLE
,如果历史表已经存在,则将其当前列定义与基表进行比较,然后通过从查询系统表发现的基表的列属性构建alter table命令并运行该命令来添加/修改/或删除列。1.对于
DROP TABLE
,删除history表(如果您想这么做的话)。此时,您有了正确的历史表结构,但没有触发器填充该表结构。
1.在事件触发器中,对于
CREATE TABLE
、ALTER TABLE
或DROP TABLE
中的任何一个,调用CreateHistoryTrigger
触发器函数,传入您关心的表名和列名。该函数需要CREATE OR REPLACE
表上的触发器,因为该触发器可能与同一表结构的先前版本不同。像这样的元编程可能是具有挑战性的,但它也是一种有趣的、“永久的”/可重用的解决问题的方法。如果你能概括你在手动编写的触发器中使用的逻辑--允许表名和列是参数--这可能并不那么难,你可以在以后的项目中重用相同的事件触发器和触发器函数。