在数据库方面,我如何确保给定类型的超类型 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.SubtypeAId
、SuprerType.SubtypeBId
非 NULL 并匹配SuperTypeId
)。延迟子 FK(或 CHECK,如果您的 DBMS 支持它)以在插入新数据时打破先有鸡还是先有蛋的问题。
1 SubtypeA.SubtypeAId
referencesSuperType.SuperTypeId
和SuperType.SubtypeAId
references 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虚拟列)使用计算列来节省存储空间。
顺便说一句,通过应用程序逻辑强制存在和排他性并不是一个糟糕的整体策略。大多数时候,您应该努力在数据库中尽可能多地执行完整性,但在这种特殊情况下,在应用程序级别执行此操作通常被认为是合理的,以避免上述复杂性。
最后,“单独表中的所有类”并不是实现继承的唯一策略。如果您使用“一个表中的所有内容”或“单独表中的具体类”来实现继承,那么强制子类型的存在性和排他性会变得容易得多。
看看这篇文章了解更多信息。