【问题标题】:What is good practice in a DB schema keeping a history of a link-table?数据库模式中保存链接表历史的良好做法是什么?
【发布时间】:2016-03-01 10:10:23
【问题描述】:

事不宜迟,举个例子:

让我们考虑一个任意的例子,3 个表,一个有工人,一个有任务,一个链接表,并考虑历史“天”的分辨率

表“工人”,(PK)id

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

表“任务”,(PK)id

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

表“task_assignments”, (PK)workers.id 作为 w_id, (FK)w_id, (FK) tasks.id 作为 t_id

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

所以现在一切似乎都清楚了,可能还有一种情况,即 t_id 是 (PK) 的一部分,在此示例中没有任何意义。链接表是直截了当的,但我如何实现良好的历史记录?

假设:

  • 我于 1970 年 1 月 1 日将 w_id(1) 分配给 t_id(2)。
  • 在 1970 年 1 月 2 日,我从他的任务中取消分配 w_id(1),没有留下任何条目 链接表。
  • 在 1970 年 1 月 8 日,我将 w_id(1) 分配给了 t_id(1),这需要更长的时间。
  • 在 1970 年 1 月 15 日,我再次从他的任务中取消分配 w_id(1),没有留下 链接表中的条目。

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

我想轻松查询:

  • w_id(?) 在 1970 年 1 月 3 日做了什么任务?
  • 什么 w_id 从 1970-01-01 到 1970-01-10 没有任务?
  • 从 1970 年 1 月 10 日到 1970 年 1 月 12 日,w_id(?) 做了哪些任务?
  • 哪些任务目前没有分配给任何工作人员?

我可以更改链接表,使其也包含一个日期戳作为 (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
------------+------+------

或者我是否应该制作某种“历史表”,但是在不加倍链接表的情况下放什么?为链接表创建一个 AI-PK 并将其与日期戳一起存储在历史表中的一行中?以及如何处理未分配的周期?

是否存在某种“模式设计模式”?我根本不知道要搜索什么,所以基本上可以接受的答案也是指向涵盖该主题的文章的链接。

【问题讨论】:

  • 你要么想使用支持 SQL:2011 Temporal 的数据库,要么使用历史表模式,在删除时复制到类似的表

标签: mysql database database-schema


【解决方案1】:

您可以使用如下所示的表 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 |
+------+

从 1970 年 1 月 1 日到 1970 年 1 月 10 日,哪些 w_id 没有任务?

 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 |
+----+

【讨论】:

  • 非常感谢您的详尽回答。没有必要对查询进行举例说明,但我想这使得它真正完整以供将来参考。如果有任何其他解决方案,我将等待更多输入,但似乎开始/结束列是最好的方法。或者换句话说,答案对我来说似乎可以接受,但如果我知道是否有任何缺点/陷阱或更好的方法,我会首先问:D
  • 一个查询不能正常工作。也许更新它? :) SELECT t_id FROM assignments WHERE w_id = 1 AND date_start = '1970-01-03'; 仅在 date_start 完全匹配并且不告诉 w_id(1) 那天在做什么时才有效。我认为应该是:SELECT t_id FROM assignments WHERE w_id = 1 AND '1970-01-03' BETWEEN date_start AND date_finish;
  • 非常感谢您的评论,我修复了答案。
猜你喜欢
  • 1970-01-01
  • 2021-11-13
  • 2018-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-22
相关资源
最近更新 更多