sql – 如何在数据库中表示继承

原文地址:https://codeday.me/bug/20170520/16907.html

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

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

在C#等等中实现它是微不足道的,因为您可以创建一个策略集合的部分,其中部分继承为各种类型的封面所需。然而,关系数据库似乎不容易这样。

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

>创建一个策略表,然后为所有可能的变体(包括所有必需的字段)生成一个Sections表,其中大部分变量都为null。
>创建一个策略表和大量节表,每种类型的封面一个。

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

这种情况的最佳做法是什么?

@Bill Karwin描述了他的SQL Antipatterns书中的三种继承模型,当提出解决方案的SQL Entity-Attribute-Value反模式。这是一个简短的概述:

单表继承(又称为每个层次结构继承)

在第一个选项中使用单个表可能是最简单的设计。正如你所提到的,许多属于子类型的属性必须在这些属性不适用的行上赋予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
>搜索所有策略,不管子类型变得困难,并且将需要一堆UNION。

这是如何查询所有策略,无论类型如何:

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 mentions in the other answer的解决方案。为您的基类创建单个表,其中包括所有公共属性。然后,您将为每个子类型创建特定的表,其主键也充当基表的foreign key。例:

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属性。
>现在,公共属性不再与子类型特定属性混合。
>我们可以呆在DRY,终于。在创建表时,不需要为每个子类型表重复公共属性。
>管理策略的自动递增ID变得更容易,因为这可以由基表处理,而不是由每个子类型表独立生成它们。
>搜索所有策略,不管子类型现在变得很容易:不需要UNION – 只是一个SELECT * FROM策略。

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

这三个模型的名字来自Martin Fowler’sPatterns of Enterprise Application Architecture

猜你喜欢

转载自blog.csdn.net/qq_32439101/article/details/86471097
今日推荐