ER图中的超级和子类型关系如何表示为表格?

时间:2012-08-20 04:41:12

标签: database database-design erd entity-relationship

我正在学习如何将实体关系图解释为SQL DDL语句,我对符号的差异感到困惑。考虑一个不相交的关系,如下图所示:

"Vehicle" box connects to "IsA" triangle, noted as "disjoint," which connects separately to "2WD" box and "4WD" box.

这会表示为:

  1. 车辆,2WD和4WD表(2WD和4WD将指向车辆的PK);或
  2. 只有2WD和4WD表(以及NO Vehicle表),这两个表都会复制Vehicle所拥有的任何属性吗?
  3. 我认为这些是写这种关系的其他方式:

    "Vehicle" box connects with a thick line to "IsA" triangle, which connects with thin lines separately to "2WD" box and "4WD" box. "Vehicle" box connects to "IsA" triangle, which connects separately to "2WD" box and "4WD" box, all by thin lines.

    我正在寻找一个明确的解释,说明每个图表最终会有哪些表格。

4 个答案:

答案 0 :(得分:19)

ER符号

有几种ER符号。我不熟悉你正在使用的那个,但很明显你试图表示一个子类型(又名继承,类别,子类,泛化层次......)。这是OOP继承的关系表亲。

在进行子类型分析时,您通常会关注以下设计决策:

  • 摘要与具体:可以实例化父级吗?在您的示例中:Vehicle是否存在还是2WD4WD 1
  • 包容与排他:可以为同一个父实例化多个子项吗?在您的示例中,Vehicle可以 2WD4WD吗? 2
  • 完整与不完整:您希望将来能够添加更多儿童吗?在您的示例中,您是否希望稍后可以将BikePlane(等...)添加到数据库模型中?

信息工程符号区分包容性和排他性子类型关系。另一方面,IDEF1X表示法没有(直接)识别这种差异,但它确实区分了完整和不完整的子类型(IE没有)。

ERwin Methods Guide(第5章,子类型关系)中的下图说明了差异:

enter image description here

IE和IDEF1X都不允许直接指定抽象与具体父级。

物理表示

不幸的是,实际数据库并不直接支持继承,因此您需要此图转换为实际表。这样做通常有3种方法:

  1. 将所有类放在同一个表中,并将子字段保留为NULL。然后,您可以使用CHECK来确保非NULL中的字段的正确子集。
    • 优点:没有加入,所以一些查询可以受益。可以强制执行父级密钥(例如,如果您想避免使用具有相同ID的不同2WD4WD个车辆。可以轻松地强制执行包容性与排他性子项以及抽象与具体父级(仅通过改变CHECK)。
    • 缺点:有些查询可能会变慢,因为它们必须过滤掉“无趣”的孩子。根据您的DBMS,特定于子项的约束可能会有问题。很多NULL都会浪费存储空间。不太适合不完整的子类型 - 添加新子项需要更改现有表格,这在生产环境中可能会有问题。
  2. 将所有子项放在单独的表中,但没有父表的表(而是在所有子项中重复父项的字段和约束)。具有(3)的大多数特征,同时避免JOIN,代价是较低的可维护性(由于所有这些字段和约束重复)以及无法强制执行父级密钥或代表具体父级。
  3. 将父级和子级放在不同的表中。
    • 优点:清洁。不需要人为地重复字段/约束。实施父级键并轻松添加特定于子级的约束。适合不完整的子类型(相对容易添加更多的子表)。某些查询只能通过查看“有趣的”子表来获益。
    • 缺点:有些查询可能很重要。可能难以强制执行包容性与独占子级以及抽象与具体父级(如果DBMS支持循环延迟外键,则可以以声明方式强制执行,但在应用程序级别强制执行它们通常被认为是较小的邪恶)。
  4. 正如您所看到的,情况并不理想 - 无论您选择何种方法,您都需要妥协。方法(3)应该是你的起点,如果有令人信服的理由,只选择其中一种方法。


    1 我猜这是你的图表中线条的粗细。

    2 我猜这是你的图表中“不相交”的存在与否。

答案 1 :(得分:3)

通常,当您在数据库设计中执行超类型/子类型关系时,需要为General Entity类型(超类型)创建单独的表,并为您的Specialized Entity版本创建单独的表(Sub) -Type)脱节与否。在您的情况下,您将需要为VEHICLE和主键创建一个表,以及一些常见或由所有子类共享的属性。然后,您将需要为2WD和4WD创建单独的表以及仅特定于这些表的属性。例如

然后您可以使用SQL联接

查询这些表

答案 2 :(得分:2)

其他响应者说了什么,以及下面的子类表的主键。

您的案例看起来像设计模式的一个实例,称为“泛化专业化”,或简称为Gen-Spec。如何使用数据库表对数组规范建模的问题一直出现在SO中。

如果您在诸如Java之类的OOPL中建模gen-spec,您将使用子类继承工具来为您处理细节。您只需定义一个类来处理通用对象,然后定义一个子类集合,每个类型对应一种特定对象。每个子类都会扩展泛化类。它简单明了。

不幸的是,关系数据模型没有内置的子类继承,据我所知,SQL数据库系统不提供任何此类工具。但你不是运气不好。您可以设计表格以与OOP的类结构平行的方式对gen-spec进行建模。然后,在将新项添加到通用类时,必须安排实现自己的继承机制。详情如下。

类结构相当简单,一个表用于gen类,一个表用于每个spec子类。这是一个很好的例子,来自Martin Fowler的网站。 Class Table Inheritance.请注意,在此图中,Cricketer既是子类又是超类。您必须选择在哪些表中使用哪些属性。该图显示了每个表中的一个示例属性。

棘手的细节是如何为这些表定义主键。 gen类表以通常的方式获取主键(除非此表是另一种泛化的特化,如Cricketers)。大多数设计师给主键一个标准名称,如“Id”。他们使用自动编号功能填充Id字段。 spec类表获得一个主键,可以命名为“Id”,但不使用自动编号功能。相反,每个子类表的主键被约束为引用通用表的主键。这使得每个专用主键成为外键和主键。请注意,在Cricketers的情况下,Id字段将引用Players中的Id字段,但Bowlers中的Id字段将引用Cricketers中的Id字段。

现在,当您添加新项目时,您必须保持参照完整性,这是如何 首先在gen表中插入一个新行,为主键提供所有属性的数据。自动编号机制生成唯一的主键。接下来,在适当的spec表中插入一个新行,包括其所有属性的数据,包括主键。您使用的主键是刚刚生成的全新主键的副本。这种主键的传播可以称为“穷人的继承”。

现在,当您希望所有通用数据与来自一个子类的所有专用数据一起使用时,您所要做的就是通过公共键连接两个表。与所涉及的子类无关的所有数据都将退出连接。它光滑,简单,快速。

答案 3 :(得分:1)

实现任何特定数据模型并不总是只有一种方法。通常,当您从逻辑模型转移到物理模型时会发生转换。

标准SQL没有一种干净的方法来强制执行不相交的子类型约束。

如果您的目标是使用模式尽可能多地执行模型规则,那么实现模型的标准方法是使用超类型的表和每个子类型的表。这确保了每个实体仅使用适用的属性。

有一个或多或少的标准SQL技巧来强制执行不相交的约束。它让一些人失望,因为它以不重要的方式违反了规范化规则。尽管如此,有些人认为这种技术具有美学上的攻击性,因为技术上违反了2NF。

此技术涉及将分区属性添加到超类型,并在每个子类型中包含此分区属性,并将其添加到子类型的主键中。除了为分区属性强加特定值的检查约束外,还可确保每个实体最多只能有一个子类型。该技术在许多地方都有详细记录,例如this blog