我想就建立数据库的最佳方式提出建议 - 它存储医疗数据。我有许多不同的实体(表格)可能有一种或多种与之相关的药物。这些通常是一对多关系,并且药物只与单个实体相关(即,它们不共享)。药物治疗数据的列是常见的。
我的问题是,我应该有一个Medication表(并使用多个多对多映射表),还是应该使用多个Medication表?
选项1 - 单一药物治疗表:
[table1]1---*[table1_has_medication]*---1[medication]
[table2]1---*[table2_has_medication]*---1[medication]
[table3]1---*[table3_has_medication]*---1[medication]
选项2 - 多个药物治疗表:
[table1]1---*[table1Medication]
[table2]1---*[table2Medication]
[table3]1---*[table3Medication]
选项1似乎更整洁,因为所有药物数据都在一个表中。然而,药物实际上只与单个表有关,因此它不是真正的多对多关系。另外,我认为我不能支持多对多关系的级联删除,因此我需要小心“孤立的"药物记录。
我对有经验的数据库设计师的意见感兴趣。谢谢。
答案 0 :(得分:1)
除了没有准确地表示您的要求之外,单个多对多(又名。"交叉点"或#34;链接")表还有另一个问题:一个FK只能引用一个表,所以要么你必须使用多个独家FK,要么你自己必须强制执行参照完整性,这比它看起来要harder to do properly。
总而言之,看起来像你需要的单独的药物表。
注意:如果您的要求发生变化并且您突然不得不从另一个表中引用所有药物,那么这可能会成为一个问题。如果发生这种情况,请考虑"继承"普通餐桌上的所有药物表。您可以从中推断an example。
答案 1 :(得分:0)
在DBA stackexchange上找到合适的答案。
以下重复:
关系数据库不是为完美地处理这种情况而构建的。你必须决定什么对你最重要,然后做出权衡。你有几个目标:
问题在于其中一些目标相互竞争。
子打字解决方案
您可以选择一种子类型解决方案,您可以在其中创建包含公司和人员的超类型。这种超类型可能具有子类型的自然键的复合键加上分区属性(例如customer_type
)。就规范化而言,这很好,它允许您强制执行参照完整性以及公司和人员相互排斥的约束。问题是这会使数据检索变得更加困难,因为当您将帐户加入帐户持有者时,您始终必须根据customer_type
进行分支。这可能意味着使用UNION
并在查询中包含大量重复SQL。
两个外键解决方案
您可以选择一种解决方案,在您的帐户表中保留两个外键,一个到公司,一个到一个人。此解决方案还允许您保持参照完整性,规范化和互斥性。它还具有与子类型解决方案相同的数据检索缺陷。事实上,这个解决方案就像子打字解决方案一样,只是你遇到了“更快”分支加入逻辑的问题。
然而,由于强制执行互斥约束的方式,许多数据建模者会认为这种解决方案不如子打字解决方案。在子类型解决方案中,您使用键来强制实现互斥性。在两个外键解决方案中,您使用CHECK
约束。我知道有些人对检查限制有不合理的偏见。这些人更喜欢将约束保留在密钥中的解决方案。
“非规范化”分区属性解决方案
还有另一种选择,您可以在chequing帐户表上保留一个外键列,并使用另一列来告诉您如何解释外键列(RoKa的OwnerTypeID
列)。这基本上通过将分区属性非规范化为子表来消除子类型解决方案中的超类型表。 (请注意,根据形式定义,这不是严格的“非规范化”,因为分区属性是主键的一部分。)这个解决方案看起来非常简单,因为它避免了额外的表来做或多或少相同的事情而且它将外键列的数量减少到一个。此解决方案的问题在于它不会避免检索逻辑的分支,而且它不允许您维护声明性引用完整性。 SQL数据库无法管理多个父表之一的单个外键列。
共享主键域解决方案
人们有时处理这个问题的一种方法是使用单个ID池,这样任何给定ID都不会混淆,无论它是属于一个子类型还是另一个子类型。这可能会在银行业务场景中很自然地发挥作用,因为您不会向公司和自然人发放相同的银行帐号。这具有避免需要分区属性的优点。您可以使用或不使用超类型表来执行此操作。使用超类型表允许您使用声明性约束来强制唯一性。否则,必须在程序上强制执行。此解决方案已规范化,但除非保留超类型表,否则不允许维护声明性参照完整性。它仍然无法避免复杂的检索逻辑。
因此,您可以看到,实际上不可能拥有遵循所有规则的干净设计,同时保持数据检索的简单性。你必须决定你的权衡取舍。