如何表示数据库中的继承? [关闭]

2023-11-23

我正在考虑如何在 SQL Server 数据库中表示复杂的结构。

考虑一个需要存储一系列对象的详细信息的应用程序,这些对象共享一些属性,但有许多其他不常见的属性。例如,商业保险套餐可能在同一保单记录中包括责任险、机动险、财产险和赔偿险。

在 C# 等中实现这一点很简单,因为您可以创建包含部分集合的策略,其中部分根据各种类型的覆盖的需要继承。然而,关系数据库似乎并不容易做到这一点。

我可以看到有两个主要选择:

  1. 创建一个策略表,然后创建一个部分表,其中包含所有可能的变化所需的所有字段,其中大部分为空。

  2. 创建一个策略表和多个部分表,每个表对应一种保险。

这两种替代方案似乎都不能令​​人满意,特别是因为需要跨所有部分编写查询,这将涉及大量连接或大量空检查。

这种情况的最佳实践是什么?


@比尔·卡尔文在他的书中描述了三种继承模型SQL 反模式书上,在提出 SQL 的解决方案时实体-属性-值反模式。这是一个简短的概述:

单表继承(又名每层次结构表继承):

在第一个选项中使用单个表可能是最简单的设计。正如您所提到的,许多特定于子类型的属性必须被赋予NULL这些属性不适用的行上的值。使用此模型,您将拥有一个策略表,如下所示:

+------+---------------------+----------+----------------+------------------+
| id   | date_issued         | type     | vehicle_reg_no | property_address |
+------+---------------------+----------+----------------+------------------+
|    1 | 2010-08-20 12:00:00 | MOTOR    | 01-A-04004     | NULL             |
|    2 | 2010-08-20 13:00:00 | MOTOR    | 02-B-01010     | NULL             |
|    3 | 2010-08-20 14:00:00 | PROPERTY | NULL           | Oxford Street    |
|    4 | 2010-08-20 15:00:00 | MOTOR    | 03-C-02020     | NULL             |
+------+---------------------+----------+----------------+------------------+

\------ COMMON FIELDS -------/          \----- SUBTYPE SPECIFIC FIELDS -----/

保持设计简单是一个优点,但这种方法的主要问题如下:

  • 当涉及到添加新的子类型时,您必须更改表以适应描述这些新对象的属性。当您有许多子类型或者您计划定期添加子类型时,这很快就会成为问题。

  • 数据库将无法强制执行哪些属性适用,哪些不适用,因为没有元数据来定义哪些属性属于哪些子类型。

  • 你也不能强制执行NOT NULL关于应该是强制性的子类型的属性。您必须在您的应用程序中处理这个问题,这通常并不理想。

具体表继承:

解决继承问题的另一种方法是为每个子类型创建一个新表,重复每个表中的所有公共属性。例如:

--// Table: policies_motor
+------+---------------------+----------------+
| id   | date_issued         | vehicle_reg_no |
+------+---------------------+----------------+
|    1 | 2010-08-20 12:00:00 | 01-A-04004     |
|    2 | 2010-08-20 13:00:00 | 02-B-01010     |
|    3 | 2010-08-20 15:00:00 | 03-C-02020     |
+------+---------------------+----------------+
                          
--// Table: policies_property    
+------+---------------------+------------------+
| id   | date_issued         | property_address |
+------+---------------------+------------------+
|    1 | 2010-08-20 14:00:00 | Oxford Street    |   
+------+---------------------+------------------+

这种设计将基本上解决单表方法所确定的问题:

  • 现在可以强制执行强制属性NOT NULL.

  • 添加新的子类型需要添加一个新表,而不是向现有表添加列。

  • 也不存在为特定子类型设置不适当属性的风险,例如vehicle_reg_no房地产政策领域。

  • 没有必要type属性与单表方法中相同。该类型现在由元数据定义:表名。

然而,这种模型也有一些缺点:

  • 公共属性与子类型特定属性混合在一起,并且没有简单的方法来识别它们。数据库也不会知道。

  • 定义表时,您必须为每个子类型表重复公共属性。那绝对不是DRY.

  • 无论子类型如何,搜索所有策略都变得很困难,并且需要一堆UNIONs.

这是您必须查询所有策略(无论类型如何)的方法:

SELECT     date_issued, other_common_fields, 'MOTOR' AS type
FROM       policies_motor
UNION ALL
SELECT     date_issued, other_common_fields, 'PROPERTY' AS type
FROM       policies_property;

请注意,添加新的子类型将需要使用额外的内容来修改上述查询UNION ALL对于每个子类型。如果忘记此操作,很容易导致应用程序出现错误。

类表继承(又名每类型继承表):

这是解决方案@David 在另一个答案中提到。您为基类创建一个表,其中包括所有公共属性。然后,您将为每个子类型创建特定的表,其主键也充当外键到基表。例子:

CREATE TABLE policies (
   policy_id          int,
   date_issued        datetime,

   -- // other common attributes ...
);

CREATE TABLE policy_motor (
    policy_id         int,
    vehicle_reg_no    varchar(20),

   -- // other attributes specific to motor insurance ...

   FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);

CREATE TABLE policy_property (
    policy_id         int,
    property_address  varchar(20),

   -- // other attributes specific to property insurance ...

   FOREIGN KEY (policy_id) REFERENCES policies (policy_id)
);

该解决方案解决了其他两种设计中发现的问题:

  • 强制属性可以通过以下方式强制执行NOT NULL.

  • 添加新的子类型需要添加一个新表,而不是向现有表添加列。

  • 没有为特定子类型设置不适当属性的风险。

  • 无需type属性。

  • 现在,公共属性不再与子类型特定属性混合。

  • 我们终于可以保持干燥了。创建表时无需重复每个子类型表的公共属性。

  • 管理自动递增id策略变得更容易,因为这可以由基表处理,而不是每个子类型表独立生成它们。

  • 现在,无论子类型如何,搜索所有策略都变得非常容易:否UNION需要 - 只是一个SELECT * FROM policies.

我认为类表方法在大多数情况下是最合适的。


这三款车型的名字来源于马丁·福勒的 book 企业应用架构模式.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何表示数据库中的继承? [关闭] 的相关文章

随机推荐

  • TreeMap 按值排序

    我想编写一个比较器 它可以让我按值而不是默认的自然顺序对 TreeMap 进行排序 我尝试了这样的事情 但无法找出出了什么问题 import java util class treeMap public static void main S
  • 如何使用Powershell或其他工具(递归)获取所有AD用户组?

    我试图在我使用的 Powershell 中获取用户所属的所有组 甚至是嵌套的组 重复地 Get ADUser
  • x86 操作码是任意的吗?

    x86 操作码是任意的吗 有没有理由hlt是 0xf4 并且nop是0x90吗 该架构的早期版本 8008 8080 是使用极少量的晶体管 逻辑门来实现的 当时 我确信设计者以易于解码的方式选择了操作码和指令格式 例如 最少的门数 这些说明
  • 如何在hadoop中执行MapReduce作业期间在控制台上打印

    我想在控制台上执行后打印 地图 的每一步 就像是 System out println 第一步完成 System out println 第二步完成 等等 是否有一个特殊的命令可以做到这一点 或者根本不可能 因为 System out pr
  • Flutter - 删除 dart 中的转义序列

    要将 API 响应字符串解码为 JSON json decode 工作正常 这将解析类似于以下内容的 JSON 字符串 Response Responsecode 1 Response Success 但就我而言 响应采用序列化形式 例如
  • SQL语法多重连接?

    我有两个表 Transaction 和 Master 事务表显示了起始和结束活动 ID 主控显示活动 ID 和名称 from 和 to id 使用相同的主表来关联活动 id 和名称 我想做的是采用不同的 from 和 to 值并用关联的名称
  • 从谷歌地图中删除 HeatmapLayer

    我正在使用 HeatmapLayer apihttps developers google com maps documentation javascript layers JSHeatMaps 我像这样生成热图 heatmap new g
  • 在C#中使用FtpWebRequest时设置端口号

    当我尝试使用 VS2008 作为调试器从 C 代码 FTP 到我的 Win 2008 服务器时 我不断收到异常 我的测试类如下所示 public class FTP private string ftpServerIP 192 168 10
  • 比较 BigDecimal

    我有以下两个 BigDecimal 对象 BigDecimal one new BigDecimal 3 0 BigDecimal two new BigDecimal 3 00 System out println one scale 0
  • 三角测量和直接线性变换

    按照 Hartley Zisserman 的多视图几何算法 12 最佳三角测量方法 p318 我得到了相应的图像点 xhat1 和 xhat2 步骤 10 在步骤11中 需要计算3D点Xhat 其中一种方法是直接线性变换 DLT 在 12
  • 如何从Java中的日期获取世纪

    如何从Java中的日期获取当前世纪 例如日期 06 03 2011 根据格式 MM dd yyyy 我怎样才能从这个日期使用当前世纪SimpleDateFormat 哈利 莱姆发布的内容略有变化 他的逻辑并不完全正确 1901 年是 20
  • 为什么要包括警卫?

    包括定义的警卫here 用于防止在编译时两次加载相同的代码 为什么我的编译器 GCC 无法检测到它正在加载相同的代码两次并具有合理的默认行为 仅仅是因为您可能希望编译器加载该文件两次 请记住 那个 include只需加载一个文件并将其内容放
  • 我可以优化 Mercurial 克隆吗?

    我的 Mercurial 克隆变得非常慢 可能是由于磁盘碎片所致 有没有办法优化它 最明显的方法是创建一个新克隆 然后将我的 MQ 保存的捆绑包 hgrc 等复制到新克隆并删除旧克隆 但似乎有人以前遇到过这个问题并进行了扩展来做到这一点 如
  • 如何使用 std::rel_ops 自动提供比较运算符? [复制]

    这个问题在这里已经有答案了 如何获得运营商 gt gt lt and from and
  • 如何在 Python 中检测文件是否为二进制(非文本)?

    在 Python 中如何判断文件是否是二进制 非文本 我正在 Python 中搜索大量文件 并不断在二进制文件中获取匹配项 这使得输出看起来非常混乱 我知道我可以使用grep I 但我对数据的处理超出了 grep 允许的范围 过去 我只会搜
  • “此链接已停用,因为它未嵌入 JSF 表单中。”

    当我使用以下命令链接时
  • 比较悬空指针合法吗?

    比较悬空指针合法吗 int p q int a p a int b q b std cout lt lt p q lt lt n 注意两者如何p and q指向已经消失的物体 这合法吗 介绍 第一个问题是使用价值是否合法p at all A
  • 如何在 Java 中合并两个 XML

    我正在尝试用 Java 合并两个 xml 我正在使用 STaX API 来编写这些 XML 我在互联网上搜索了很多关于如何合并 xml 的信息 但没有一个看起来像C 有没有使用 StAX 在 Java 中执行此操作的直接方法 xslt 可能
  • 您如何组织版本控制存储库?

    首先 我知道这一点 您将如何为内部软件项目组织 Subversion 存储库 接下来 实际问题 我的团队正在重组我们的存储库 我正在寻找有关如何组织它的提示 在本例中为 SVN 这就是我们的想法 我们有一个存储库 多个项目和多个 svn e
  • 如何表示数据库中的继承? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 我正在考虑如何在 SQL Server 数据库中表示复杂的结构 考虑一个需要存储一系列对象的详细信息的应用程序 这些对象共享一些属性 但有许多其他不常见的属性 例如 商业保险套餐可能在同一