【问题标题】:Canonical way to prevent many to many join table from having duplicates when joining with self与自我连接时防止多对多连接表重复的规范方法
【发布时间】:2017-10-14 09:32:21
【问题描述】:

我正在为数据库项目建模一所学校,并且我有一个多对多的关系,将一个 course 表与其自身连接以建立先决条件。该表(简化)如下所示:

CREATE TABLE course_prereqs (
  course_id INT NOT NULL,
  prereq_id INT NOT NULL,

  PRIMARY KEY (course_id, prereq_id),
  FOREIGN KEY (course_id) REFERENCES course (course_id),
  FOREIGN KEY (prereq_id) REFERENCES course (course_id)
)

我想知道的是最简单但也是最用户友好的方法,您可以防止 (1, 2), and (2, 1) 成为表中的先决条件,因为它会导致循环依赖。

我在想类似的东西

-- in a trigger though since MySQL doesn't have check
CHECK (course_id < prereq_id) 

虽然这样可行,但我觉得最终用户始终确保course_id 始终小于prereq_id 可能会很烦人。

有没有更好的方法,还是我高估了必须确保course_id 总是更小的不便?

【问题讨论】:

    标签: mysql sql database database-design many-to-many


    【解决方案1】:

    这似乎是一个应用程序问题。当说“课程 #1 是课程 #2 的‘先决条件’”时,稍后说“课程 #2 是课程 #1 的先决条件”是不正确的。也就是说,为什么您需要让数据库检查不应该发生的事情?

    另一方面,如果“关系”是自反的(1->2 意味着 2->1),那么我会这样做:

    INSERT IGNORE (a, b) VALUES (LEAST($this, $that), GREATEST($this, $that));
    

    因此存在用于存储关系的“规范”顺序。测试变得更加混乱。

    或者...存储两个关系。它只有两倍的行数,但查找性能并没有明显下降。

    在这两种情况下,您都需要两个索引:

    PRIMARY KEY(a, b),
    INDEX      (b, a)
    

    【讨论】:

    • 这一切都说得通,但是……嗯……为什么是应用程序问题?数据库的工作不是强制执行两门课程不能成为彼此的先决条件这一事实吗?例如,如果另一个答案中的 select 语句不等于 0,则引发错误的触发器。
    • @AR7 - 数据库无法区分“课程”和“先决条件”。因此,如果 #1 确实是 #2 的先决条件,但您首先插入 course=1,prerequisite=2,它将不会被捕获。稍后,prerequisite=1, course=2的正确插入将被标记为错误。
    【解决方案2】:

    在插入新课程之前检查cnt = 0

    select count(1) cnt from course_prereqs where course_id = new_prereq_id and prereq_id = new_course_id
    

    【讨论】:

      猜你喜欢
      • 2021-06-22
      • 2014-06-13
      • 2021-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-13
      • 2021-07-31
      相关资源
      最近更新 更多