链接表是否可以有两个互斥的列?

Rob*_*Dam 0 mysql database-design constraints foreign-keys

我有一个问题,由于以前人们的设计决策不好,我被迫在链接表中有两列始终互斥.我见过SQL-Server:将列定义为互斥但MySQL不强制执行CHECK约束,所以我正在寻找其他选项.有没有办法在两列之间强制互斥?

让我解释一下如果有人看到更好的解决方案.

以前的dev/admins构建了两个表,它们基本上记录了相同类型的东西.我有一个新的表,理论上是1 - >他们都代表的东西.所以我的两个选项似乎是创建两个桥接表或一个带有两个外部键引用的桥接表.对于我来说,这两个表似乎是一个丑陋的解决方案,我希望避免这种情况,但是未强制的互斥字段使我容易受到腐败的影响.

具体的例子,因为我不能分享我的真实案例:

Table 'full_time_students' stores full time students
Table 'part_time_students' store part time students

Table 'class' will store class info
Table 'class_students' should store which students are in which class
Run Code Online (Sandbox Code Playgroud)

在一个理想的世界里,我会把两个学生表结合起来,但是有很多代码会破坏,我没有时间/意愿去修复所有这些,所以我现在不得不处理现有的模式/数据.我正在使用InnoDB,所以我已经计划在student_ids上设置外键约束,但就像我说的那样,如果我用一个包含两列的表格,我就会打开自己的行,同时使用两个ID.

写出来几乎说服我重新考虑2表解决方案......

Per*_*DBA 5

在回应评论时重写.

我不同意任何答案.

没有什么可以担心"更多"表,这是关系数据库的本质; 特别是如果你想要Relational的强大功能,并允许用户访问数据库而无需通过你的应用程序.

我假设有两件事:

  1. 您认为之前的开发人员犯了一个错误,因为StudentFullTime和StudentPartTime应合并为Student,因为他们有许多常见的列

  2. 您有一个新的需求类需要Class和Student之间的多对多关系.

    • 在关系术语中,称为关联表:在逻辑模型中,它显示为:: n关系(无表); 在物理模型中,它呈现为表格.(当然,如果它有列,那么它会在逻辑模型中显示为实体,而不是关系.)

好的,(1)不正确.正如将未标准化的公共列放入单个表中是错误的,使单个表具有不适用的列(Nullable列)也是错误的.他们应该做的是实施三个表格 ; 不是一个; 而不是两个,在普通的子类型超类型集群中.

  • 超类型包含公共列和一个微分器,每个子类型包含私有列.超类型和子类型之间的关系是一对一的.这是非常强大的,因为(a)它消除了歧义(存在于单个非规范化表中),(b)消除了空值,(c)最重要的是,允许这些私有列上的任何索引简单而独特(到期)没有空值).

    • 我的所有数据模型都符合 IDEF1X 标准.为了帮助那些刚接触IDEF1X的人,这里有一个解释 IDEF1X Notation 文档的文档.如果你不明白圆圈,酒吧和乌鸦脚是什么意思; 或者关系线上的内容什么意思; 或者为什么水平线就在哪里,请立即阅读.

规范化之前

所以你来了,你需要实现(2).生活对所有人来说都很容易,因为数据库是标准化的:你可以添加你需要的东西,而不必改变现有的表结构,或者扰乱任何现有的代码.

归一化后

但是他们没有这样做,他们在"数据库"中留下了两个Unnormalised表.

所以你来了,你需要实现(2).在寻找"互斥"列时,您已经确定了标准化错误(在您身边).您需要的n :: n关联表实际上是具有学生的类; 在确认基本需求后,他们可能是FullTime或PartTime的事实是一个令人担忧的进展.在考虑到这种需求之后,当然,你必须实现能够处理两种类型学生的东西.

  • 如果你实现一个表,这是一个严重的错误,你需要一个dbms,它会做一些有趣的事情,比如"互斥"

  • 如果你实现了两个表,那么你只是在复合它们的错误.这将最终受到限制,你的SQL代码将是丑陋的.

他们的错误由你推动

所要求的是,让你在你身边规范化,从而避免阻碍数据库的力量.

归一化你的

  • 一个表用于关联表,一个表用于两个子类型(基于两个子标准表的存在).简单的子类型超类型1 :: 1集群.

  • 没有空,完整,完整性,FK,可引用性等.每个表上的简单唯一索引.想想你的代码会是什么样子.

  • 如果不是现在,那么在将来,当您需要将列添加到关联表时(就像您今天需要添加表一样),您可以将它们添加到一个位置.如果你复制了他们的错误,你必须将这些列放在两个地方.

并且请迁移现有密钥,它们已经足够且已经有意义,不要创建新的IDENTITY密钥.

  • @Rob:谢谢,实际上这并不需要我很长时间。修改了我的答案,使内联有意义。提供链接,以便您可以解释 IDEF1X 符号。我通过简单的标准化消除了“互斥”问题,因此我们没有回到第一个方向。“链接”是直接的 FK,没有任何隐藏的内容。ClassStudent.ClassId⇢ClassStudentFullTime.ClassId。后者 PK 是复合键(ClassId,Student[Type]Id)。搜索速度非常快;如果使用这两列,则支持覆盖查询。 (2认同)