外键引用多个表

Jak*_*ake 2 database sql-server database-design relational-database database-schema

我有一个带有uniqueidentifier的列,可以引用四个不同的表中的一个.我已经从两个方面看到了这一点,但两者似乎都是不好的做法.

首先,我看到了一个ObjectID列,没有明确地将其声明为特定表的外键.然后你可以推送你想要的任何uniqueidentifier.这意味着您可能会从不属于我想要的4个表的表中插入ID.

其次,因为数据可以来自四个不同的表,我也看到人们制作了4个不同的外键.并且在这样做时,系统依赖于具有非NULL值的ONE AND ONLY ONE列.

这样做有什么好办法?例如,我的表中的记录可能会引用医院(ID),诊所(ID),学校(ID)或大学(ID)......但仅限于那些表.

谢谢!

Phi*_*ley 6

您可能需要考虑Type/SubType数据模型.这与面向对象编程中的类/子类非常相似,但实现起来更加笨拙,并且没有RDBMS(我知道)本身支持它们.一般的想法是:

  • 您定义一个Type(Building),为它创建一个表,给它一个主键
  • 您定义了两个或更多子类型(此处为Hospital,Clinic,School,University),为每个子类创建表,生成主键...但主键也是引用Building表的外键
  • 现在可以使用外键在Building表上构建具有一个"ObjectType"列的表.您必须加入几张桌子来确定它是什么类型的建筑物,但无论如何您都必须这样做.那,或存储冗余数据.

您已经注意到此模型的问题,对吧?什么是让建筑物在两个或多个子类型表中都有条目?很高兴你问:

  1. 在Building中添加一个列,也许是"BuildingType",比如char(1),允许值为{H,C,S,U},表示(duh)建筑类型.
  2. 在BuildingID + BuildingType上构建唯一约束
  3. 在子表中有BulidingType列.对它进行检查约束,以便它只能设置为值(Hospitals表的H等)理论上,这可以是计算列; 在实践中,由于以下步骤,这将无法工作:
  4. 构建外键以使用两列关联表

Voila:给定一个类型为H的BUILDING行,不能将SCHOOL表中的条目(类型S)设置为引用该构建

你会记得我确实说它很难实现.

事实上,最大的问题是:这值得吗?如果有意义的是将四种(或更多,如时间)建筑类型实现为类型/子类型(进一步的规范化优势:一个地址用于地址和每个建筑物共有的其他属性,特定于建筑物的属性存储在子表中),构建和维护可能值得付出额外的努力.如果没有,那么你就回到原点:一个在现代普通RDBMS中难以实现的逻辑模型.


Wal*_*tty 5

让我们从概念层面开始。如果我们将医院、诊所、学校和大学视为主题实体的类,是否有一个超类可以概括所有这些实体?大概有。我不会试图告诉你它是什么,因为我不像你那样理解你的主题。但是我将继续进行,好像我们可以将所有这些都称为“机构”,并将这四个中的每一个都视为机构的子类。

正如其他响应者所指出的,大多数关系数据库系统中都没有内置类/子类扩展和继承。但是,如果您知道正确的流行语,还有很多帮助。以下内容旨在教您使用数据库行话中的流行语。以下是即将到来的流行词的摘要:“ER 泛化”、“ER 特化”、“单表继承”、“类表继承”、“共享主键”。

停留在概念层面,ER 建模是在概念层面理解数据的好方法。在 ER 建模中,有一个概念“ER 泛化”和一个对应概念“ER 专业化”,它们与我刚刚在上面作为“超类/子类”提出的思维过程平行。ER Specialization 告诉您如何绘制子类,但它没有告诉您如何实现它们。

接下来我们从概念层向下移动到逻辑层。我们根据关系或 SQL 表(如果您愿意)来表示数据。有几种实现子类的技术。一种称为“单表继承”。另一种叫做“类表继承”。关于类表继承,还有另一种名为“共享主键”的技术。

在类表继承的情况下,我们首先设计一个名为“机构”的表,其中包含一个 Id 字段、一个名称字段以及与机构相关的所有字段,无论它们是这四种中的哪一种。例如,诸如邮寄地址字段之类的东西。同样,您比我更了解您的数据,并且您可以找到所有四个现有表中的字段。我们以通常的方式填充 id 字段。

接下来我们设计四个表,分别称为“医院”、“诊所”、“学校”和“大学”。这些将包含一个 id 字段,以及仅与该类型机构有关的所有数据字段。例如,医院可能有“床位容量”。同样,您比我更了解您的数据,并且您可以从现有表中的字段中找出这些字段,这些字段没有包含在机构表中。

这就是“共享主键”的用武之地。当在“机构”中创建一个新条目时,我们必须在四个专门的子类表之一中创建一个新的并行条目。但是我们不使用某种自动编号功能来填充 id 字段。相反,我们将“机构”表中 id 字段的副本放入子类表的 id 字段中。

这是一项小工作,但好处是值得付出努力的。共享主键强制执行子类条目和超类条目之间的一对一关系。它使连接超类数据和子类数据变得简单、容易和快速。它消除了通过特殊字段来告诉您给定机构属于哪个子类的需要。

而且,就您而言,它为您的原始问题提供了方便的答案。您最初询问的外键现在始终是机构表的外键。而且,由于共享主键的魔力,外键还引用了相应子类表中的条目,无需额外工作。

为方便起见,您可以创建四个视图,将机构数据与四个子类表中的每一个相结合。

在网上和 SO 中查找“ER 专业化”、“类表继承”、“共享主键”,也许还有“单表继承”。SO中的大多数概念或技术都有标签。