在保留 link-table 历史记录的数据库模式中,什么是好的做法?

What is good practice in a DB schema keeping a history of a link-table?

事不宜迟举个例子:

让我们考虑一个任意的例子,3 tables,一个有工人,一个有任务,一个 link table 并考虑历史的分辨率 'days'

Table "workers", (PK)id

id | name
---+-----------
 1 | Frank
 2 | Sam
 3 | Tony
---+-----------

Table "tasks", (PK)id

id | name
---+--------------------
 1 | walking the dog
 2 | feeding the cat
 3 | charging the robot
---+--------------------

Table"task_assignments", (PK)workers.id as w_id, (FK)w_id, (FK) tasks.id as t_id

w_id | t_id
-----+------
 1   |  2
 2   |  3
 3   |  2
-----+------

所以现在一切似乎都很清楚,在这个例子中,t_id 是 (PK) 的一部分可能也没有意义。 link table 很简单,但我如何实现良好的历史记录?

假设:

如何正确实现此历史记录以实现数据一致性和便于查询?

我想轻松查询:

我可以更改 link-table 以包含日期戳作为 (PK) 的一部分并以这种方式存储分配并简单地使用 t_id 存储一个新行=null 像这样取消分配?

 date_set   | w_id | t_id 
------------+------+------
 1970-01-01 | 1    | 2
 1970-01-02 | 2    | 3
 1970-01-01 | 3    | 2
 1970-01-02 | 1    | null
------------+------+------

或者我是否制作某种 "history-table" 但是在不加倍 link-table 的情况下放什么?为 link table 创建一个 AI-PK 并将其存储在带有日期戳的历史记录 table 中的一行中?以及如何处理未分配的周期?

是否有某种 "schema design patter" 用于此?我根本不知道要搜索什么,所以基本上接受table 的答案也会是对涵盖该主题的文章的 link。

您可以使用 table assignments 如下所示:

 date_start | date_finish | w_id | t_id 
------------+-------------+------+-----
 1970-01-01 | 1970-01-02  | 1    | 2
 1970-01-01 | 1970-01-02  | 3    | 2
 1970-01-02 | null        | 1    | 2
 1970-01-02 | null        | 1    | 3
------------+-------------+------+------

使用此代码添加一些测试数据:

CREATE table workers (
 id int,
 name text,
 primary key (id)
);

CREATE table tasks (
 id int,
 name text,
 primary key (id)
);

CREATE table assignments (
 w_id int,
 t_id int,
 date_start date,
 date_finish date
);

INSERT INTO workers VALUES (1, 'worker_a'), (2, 'worker_b'), (3, 'worker_c');
INSERT INTO tasks VALUES (1, 'task_1'), (2, 'task_2'), (3, 'task_3');

INSERT INTO assignments VALUES (1, 2, '1970-01-01', '1970-01-02'), (3, 2, '1970-01-01', '1970-01-02'), (1, 2, '1970-01-03', NULL), (1, 3, '1970-01-02', NULL);

现在我们可以试验所需的查询。

w_id(1) 在 1970-01-03 做什么任务?

SELECT t_id FROM assignments WHERE w_id = 1 AND '1970-01-03' BETWEEN date_start AND date_finish;
+------+
| t_id |
+------+
|    2 |
+------+

哪些 w_id 从 1970-01-01 到 1970-01-10 没有任务?

 SELECT distinct id FROM workers WHERE id NOT IN (SELECT w_id FROM assignments WHERE ( (date_start <= '1970-01-01' AND date_finish IS NULL) OR (date_start <= '1970-01-01' AND date_finish >= '1970-01-01') OR (date_start >= '1970-01-01' AND date_start <= '1970-01-10')));
+----+
| id |
+----+
|  2 |

+----+

从 1970-01-03 到 1970-01-12,w_id(1) 在做什么任务?

SELECT t_id FROM assignments WHERE w_id = 1 AND ( (date_start >= 1970-01-03 AND date_finish IS NULL) OR (date_start >= 1970-01-03 AND date_finish <= 1970-01-12));
+------+
| t_id |
+------+
|    2 |
|    3 |
+------+

哪些任务目前没有分配给任何工作人员? (假设今天是 1970-02-01)

SELECT distinct id FROM tasks WHERE id NOT IN (SELECT t_id FROM assignments WHERE ( (date_start <= '1970-02-01' AND date_finish IS NULL) OR (date_start <= '1970-02-01' AND date_finish >= '1970-02-01') OR (date_start >= '1970-02-01' AND date_start <= '1970-02-01')));
+----+
| id |
+----+
|  1 |
+----+