5

我有一个关于关系数据库中超类型子类型设计的问题。如果我有一个带有两个子类型表的超类型,我会将与两个子类型表的 PK 相关的超类型的 PK 作为 FK。假设我有这样的事情:

类型

类型 ID PK

超类型

ID PK 类型ID FK

亚型A

ID PK,FK

亚型B

ID PK,FK

在数据库方面,我如何确保给定类型的超类型 ID 仅放入适当的子类型表中?例如,我不希望将类型 A 的超类型 ID 放入 SubtypeB 表中。有没有办法轻松地防止这种情况发生在数据库端?我知道这可以在代码中处理,但是如果代码有错误怎么办?或者如果有人在其中一个子类型表中手动输入了错误的 ID 怎么办?我想我正在寻找某种方法来使这在数据库方面成为不可能。

有任何想法吗?也许 Supertype 表上的 PK 应该是 ID 和 TypeID 组合,在 ID 列上具有唯一约束,以防止两种类型都在 SuperType 表中的记录......然后 Subtype 表将具有组合 ID 和 TypeID PK对 TypeID 的约束只能是相应子类型表的类型?

4

2 回答 2

12

在数据库方面,我如何确保给定类型的超类型 ID 仅放入适当的子类型表中?

在支持延迟约束的 DBMS 上,您可以执行以下操作:

在此处输入图像描述

具有以下约束SuperType

CHECK (
    (
        (SubtypeAId IS NOT NULL AND SubtypeAId = SuperTypeId)
        AND SubtypeBId IS NULL
    )
    OR
    (
        SubtypeAId IS NULL
        AND (SubtypeBId IS NOT NULL AND SubtypeBId = SuperTypeId)
    )
)

这些特殊的圆形 FK 1与 CHECK 相结合确保了子元素的排他性存在性(CHECK 确保了以下各项之一:SuprerType.SubtypeAIdSuprerType.SubtypeBId非 NULL 并匹配SuperTypeId)。延迟子 FK(或 CHECK,如果您的 DBMS 支持它)以在插入新数据时打破先有鸡还是先有蛋的问题。

1 SubtypeA.SubtypeAId referencesSuperType.SuperTypeIdSuperType.SubtypeAIdreferences SubtypeA.SubtypeAId,其他子类型同上。

如果您的 DBMS 不支持延迟约束,您可以允许(在 CHECK 中)两个字段都为 NULL 并放弃强制执行孩子的存在(您仍然保持排他性)。


或者,也可以像这样强制执行排他性(但不存在):

在此处输入图像描述

SuperType {SuperTypeId, TypeId}注意:如果 DBMS 不支持“out-of-key”FK,您可能需要添加一个冗余的 UNIQUE 。

具有以下约束SubtypeA

CHECK(TypeId = 1)

以及以下约束SubtypeB

CHECK(TypeId = 2)

我用 1 和 2 来表示特定的子类型——你可以使用任何你喜欢的东西,只要你是一致的。

TypeId此外,您可以考虑通过为子类型(例如 Oracle 11虚拟列)使用计算列来节省存储空间。


顺便说一句,通过应用程序逻辑强制存在和排他性并不是一个糟糕的整体策略。大多数时候,您应该努力在数据库中尽可能多地执行完整性,但在这种特殊情况下,在应用程序级别执行此操作通常被认为是合理的,以避免上述复杂性。


最后,“单独表中的所有类”并不是实现继承的唯一策略。如果您使用“一个表中的所有内容”或“单独表中的具体类”来实现继承,那么强制子类型的存在性和排他性会变得容易得多。

看看这篇文章了解更多信息。

于 2012-09-04T10:37:42.167 回答
0

使用触发器将超类型表中的新条目传播到适当的子类型表。

于 2012-09-04T10:02:59.940 回答