如何用 UNIQUE 索引和外键表示它?

por*_*ton 0 foreign-key database-design

“组”是一群学生。“话题”是课程的话题。

每个组对应一个主题。(因此每个主题可能有多个组。)

一个学生对应多个组,但每个主题最多一个组。

如何根据 MySQL 中的 UNIQUE 索引和外键实现这一点?

ype*_*eᵀᴹ 7

这是一个常见的问题。“诀窍”是:

  • 添加Groups- 除了主键 - 上的冗余唯一约束(Topic, Group)
  • 这允许您TopicParticipates关系中添加属性和
  • 强制您将外键约束从 修改为ParticipatesGroups因此它Topic不仅包括Group.
  • 然后您可以添加一个唯一约束Participates (Pupil, Topic)(意味着学生只能参与一个主题一次,而不是两次或更多,这是想要的结果。)

    Topics
      Topic  PK
    
    Lessons
      Lesson PK 
      Topic         FK -> Topics
    
    Groups
      Group  PK UQ1
      Topic     UQ1 FK -> Topics  
    
    Pupils
      Pupil  PK
    
    PupilParticipatesInGroup
      Pupil  PK UQ1 FK1 -> Pupils
      Group  PK     FK2 -> Groups
      Topic     UQ1 FK2 
    
    Run Code Online (Sandbox Code Playgroud)

附录

 Abbreviation   Constraint
 ------------   -----------
   PK           Primary Key
   UQ           Unique 
   FK           Foreign Key
Run Code Online (Sandbox Code Playgroud)

请注意,设计已经完成,3NF并且Topics只有在大多数 DBMS 中的实现才需要冗余的唯一约束(因此强制执行外键。)

唯一的另一个问题是Group -> Topic关系中的依赖Participates关系导致架构违反BCNF

在链接页面的Achievability of BCNF段落,您将看到已证明并非所有表都可以分解为满足BCNF并保留原始表中的依赖关系的表。提供的示例与Participates此处的表格非常相似:

在某些情况下,非 BCNF 表无法分解为满足 BCNF 并保留原始表中的依赖关系的表。Beeri 和 Bernstein 在 1979 年表明,例如,一组函数依赖{AB ? C, C ? B}不能用 BCNF 模式表示。 [6] 因此,与前三种范式不同,BCNF 并不总是可以实现的。

尽管如此,让我们再做一个改变,以解决这个问题(如果可以的话!):


让我们来看看如果我们从(好像它从未存在过)Primary Key (Group)约束中移除(Groups并把唯一的放在它的位置)会发生什么。让我们也改变主键Participates- 注意 - 恰好是我们从一开始的目标的唯一约束. 设计变为(前两个表保持不变,因此省略):

    Groups
      Group  PK 
      Topic  PK     FK -> Topics  

    Pupils
      Pupil  PK

    PupilParticipatesInGroup
      Pupil  PK     FK1 -> Pupils
      Group         FK2 -> Groups
      Topic  PK     FK2 
Run Code Online (Sandbox Code Playgroud)

根本没有多余的列。魔法!这ParticipatesGroupsand之间常见的多对多关系Pupils(正如我们的模型所希望的那样),并且两个外键引用相应表的主键。

所以发生了什么事?魔法?(不是真的,不是) 不是Group仍然是 的候选键Groups吗?(无论如何,删除它只是一个思想实验。)如果从实际表中省略这个约束,我们会不会失去一些东西?


问题 - 以及为什么上述解决它 - 是您尝试建模的唯一约束需要关系中的Topic属性Participates。因此,您必须使用Groups复合和包含的候选键Topic。它不一定是(Topic, Group)。它可能是其他一些组合。还有哪些其他属性Groups

如果,例如,有一个属性OrderNoGroups(Topic, OrderNo)是唯一的,那么我们能有这样的设计(终于)在没有冗余,没有多余的属性,所有的约束都没有和架构是!BCNF

    Groups
      Group   PK 
      Topic      UQ1 FK -> Topics
      OrderNo    UQ1

    Pupils
      Pupil   PK

    PupilParticipatesInGroup
      Pupil   PK     FK1 -> Pupils
      Topic   PK     FK2 -> Groups
      OrderNo        FK2 
Run Code Online (Sandbox Code Playgroud)