sql server—如何在数据库中表示继承?

avwztpqn  于 2021-06-18  发布在  Mysql
关注(0)|答案(8)|浏览(294)

我正在考虑如何在SQLServer数据库中表示一个复杂的结构。
考虑一个应用程序,它需要存储一系列对象的详细信息,这些对象共享一些属性,但有许多其他不常见的属性。例如,商业保险套餐可能包括同一保单记录中的责任险、汽车险、财产险和赔偿险。
在c#等中实现这一点很简单,因为您可以创建一个包含节集合的策略,其中节是根据各种类型的保险单的需要继承的。然而,关系数据库似乎并不容易做到这一点。
我可以看到有两个主要的选择:
为所有可能的变体创建一个策略表,然后创建一个节表,其中包含所有必需的字段,其中大部分为空。
创建一个policy表和多个section表,每种cover对应一个。
这两种方法似乎都不能令人满意,尤其是在需要跨所有部分编写查询时,这将涉及大量连接或大量空检查。
这种情况下的最佳实践是什么?

6jygbczu

6jygbczu1#

或者,考虑使用本机支持丰富数据结构和嵌套的文档数据库(如mongodb)。

s4chpxco

s4chpxco2#

我倾向于方法#1(一个统一的节表),以便有效地检索整个策略及其所有节(我假设您的系统将做很多)。
此外,我不知道您使用的是哪个版本的SQLServer,但在2008年,稀疏列有助于优化性能,因为在这种情况下,列中的许多值都将为null。
最终,您必须决定策略部分的“相似性”。除非他们有实质性的不同,我认为一个更规范化的解决方案可能会比它的价值更麻烦。。。但只有你能打电话

mdfafbf1

mdfafbf13#

此外,在daniel vassallo解决方案中,如果您使用sql server 2016+,我还使用了另一种解决方案,在某些情况下不会造成性能损失。
您可以创建一个只包含公共字段的表,并添加一个包含所有子类型特定字段的json字符串的列。
我已经为管理继承测试了这个设计,我很高兴我可以在相关的应用程序中使用这种灵活性。

iqjalb3h

iqjalb3h4#

看看我在这里给出的答案
fluent-nhibernate合成键一对一Map

rbl8hiat

rbl8hiat5#

@billkarwin在他的sql反模式书中描述了三种继承模型,当时他提出了sql实体属性值反模式的解决方案。以下是简要概述:

单表继承(也称为每层次表继承):

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

+------+---------------------+----------+----------------+------------------+
| 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 属性作为单表方法中的属性。类型现在由元数据定义:表名。
然而,这种模式也有一些缺点:
公共属性与特定于子类型的属性混合在一起,没有简单的方法来识别它们。数据库也不会知道。
定义表时,必须为每个子类型表重复公共属性。那绝对不干。
无论子类型如何,都很难搜索所有策略,并且需要大量的 UNION s。
这是您必须查询所有策略的方式,而不考虑其类型:

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 .
我认为类表方法在大多数情况下是最合适的。
这三个模型的名称来自martinfowler的《企业应用程序体系结构模式》一书。

anhgbhbe

anhgbhbe6#

第三个选项是创建一个“policy”表,然后创建一个“sectionsmain”表,该表存储跨节类型通用的所有字段。然后为每种类型的节创建其他表,这些表只包含不常见的字段。
决定哪一个是最好的主要取决于您有多少字段以及您希望如何编写sql。他们都会工作。如果你只有几个字段,那么我可能会选择1。有了“很多”字段,我会倾向于2或3。

bsxbgnwa

bsxbgnwa7#

根据提供的信息,我将对数据库进行建模,使其具有以下特性:

政策

策略id(主键)

负债

密码(主键)
策略id(外键)

属性

属性\u id(主键)
策略id(外键)
…以此类推,因为我希望策略的每个部分都有不同的属性。否则,可能只有一个 SECTIONS 除了 policy_id ,会有一个 section_type_code ...
无论哪种方式,这都允许您支持每个策略的可选部分。。。
我不明白您对这种方法有什么不满意的地方—这就是您在保持引用完整性和不复制数据的同时存储数据的方式。术语是“标准化”。。。
因为sql是基于集合的,所以它与过程/oo编程概念相当陌生&需要代码从一个领域转换到另一个领域。orm经常被考虑,但是它们在高容量、复杂的系统中不能很好地工作。

qqrboqgw

qqrboqgw8#

另一种方法是使用 INHERITS 组件。例如:

CREATE TABLE person (
    id int ,
    name varchar(20),
    CONSTRAINT pessoa_pkey PRIMARY KEY (id)
);

CREATE TABLE natural_person (
    social_security_number varchar(11),
    CONSTRAINT pessoaf_pkey PRIMARY KEY (id)
) INHERITS (person);

CREATE TABLE juridical_person (
    tin_number varchar(14),
    CONSTRAINT pessoaj_pkey PRIMARY KEY (id)
) INHERITS (person);

因此,可以在表之间定义继承。

相关问题