【问题标题】:Store previous many-to-many relationships存储以前的多对多关系
【发布时间】:2021-09-25 15:01:41
【问题描述】:

我正在学习 SQL,并且有一个关于存储以前的多对多关系的问题。

我有一个学生实体和一个导师实体,它们通过关联表耦合在一起。如果学生要更换导师,我想存储该学生以前的导师。

我目前的解决方案是使用另一个关联表,但是我想知道是否有更好的解决方案来解决这个问题?

【问题讨论】:

  • 视情况而定。另一种选择可能是引入有效间隔(字段valid_from_dtvalid_to_dt)并添加具有新有效间隔的新行。如果您将当前记录的上限设置为诸如date '9999-12-31' 之类的“无穷大”并按该日期进行分区,则它应该在当前状态下显示出良好的性能。此外,对于历史数据的查询也非常方便,因为您只需在该时间间隔内输入一些日期,但它们不会那么快,您未来的所有查询都应该使用该日期。
  • 基本上你在谈论为这个特定元素构建一个审计日志。我会考虑你真正需要多少审计日志(这意味着如果你有大量的审计要求,可能会建立一个用于更改数据捕获的流程)。这是一个更高级的概念,最佳实践标准可能会从 RDBMS 变为 RDBMS。

标签: sql database postgresql database-design entity-relationship


【解决方案1】:

这取决于完整的情况。通常,将所有关联保存在单个关联表中更简单、更有效。像这样:

CREATE TABLE works_with (
  student_id int NOT NULL REFERENCES students
, tutor_id   int NOT NULL REFERENCES tutors
, start_date date NOT NULL
, end_date   date
, termination_reason text
, PRIMARY KEY (student_id, tutor_id, start_date)
, CONSTRAINT end_not_before_start
     CHECK (end_date >= start_date)
, CONSTRAINT
     CHECK (end_date IS NOT NULL OR termination_reason IS NULL)
, CONSTRAINT no_overlapping_date_range
     EXCLUDE USING gist (student_id with =, tutor_id with =, daterange(start_date, end_date) WITH &&)
);

PK 现在包括start_date,因为随着时间的推移,同一个学生和导师可能会反复合作。由于排除约束(见下文)无论如何都会防止重叠条目,因此您也可以使用额外的代理 PK 列(如 serialIDENTITY 列)。可能会更有效率。

检查约束end_not_before_start 禁止在开始之前结束(同时仍然允许end_date IS NULL

检查约束termination_reason_only_if_terminated 只允许终止关联的终止原因中的值。

排除约束no_overlapping_date_range 不允许每个学生-导师组合的日期范围重叠。 (您可能想要也可能不想要。)
需要additional module btree_gist。每个数据库安装一次:

CREATE EXTENSION btree_gist;  -- once per db

见:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 2012-04-01
    • 2016-10-18
    相关资源
    最近更新 更多