database - 超型-亚型数据库设计

标签 database database-design

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

类型

类型ID公钥

父类(super class)型

ID主键 类型ID FK

亚型A

ID PK,FK

亚型B

ID PK,FK

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

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

最佳答案

On the database side, how would I ensure that Supertype ID's of a given type were only put into the appropriate subtype table?

在支持延迟约束的 DBMS 上,您可以这样做:

enter image description here

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)
    )
)

这些奇特的循环 FKs1 与 CHECK 相结合确保子级的排他性存在(CHECK 确保恰好是以下之一:SuprerType.SubtypeAIdSuprerType.SubtypeBId 是非 NULL 且匹配 SuperTypeId)。延迟子 FK(或 CHECK,如果您的 DBMS 支持的话)以在插入新数据时打破先有鸡还是先有蛋的问题。

1 SubtypeA.SubtypeAId 引用 SuperType.SuperTypeIdSuperType.SubtypeAId 引用 SubtypeA.SubtypeAId,其他子类型同上。

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


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

enter image description here

注意:如果 DBMS 不支持“键外”FK,您可能需要在 SuperType {SuperTypeId, TypeId} 上添加冗余 UNIQUE。

SubtypeA 上有以下约束:

CHECK(TypeId = 1)

SubtypeB 的以下约束:

CHECK(TypeId = 2)

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

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


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


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

看看this post了解更多信息。

关于database - 超型-亚型数据库设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12255731/

相关文章:

Android SQLite 获取 CursorIndexOutOfBoundsException

database - NoSQL 数据库和报告

sql - 处理数据库中的魔数(Magic Number)有哪些好的策略?

java - 将文件保存为 lob 还是 OS 文件?

java - 通过 API 调用获取图像,然后从本地保存并提供以供重复查看

sql - 是自己做唯一约束还是作为主键?

database - 如何从转储文件中获取oracle数据库版本

mysql - 查询混淆创建查询而不创建 View

mysql - 考勤系统MongoDB设计

iPhone - 使用 TEXT 主键的 SQLite