根据我对您的规范的解释,您想找到一种方法来实现两个不同的(但相互连接的)超型子类型结构。
为了展示一种实现上述任务的方法,我将在所讨论的场景中添加称为和的两个经典的假设实体类型,下面将详细介绍。Foo
Bar
商业规则
以下是一些有助于我创建逻辑模型的语句:
A Foo is either one Bar or one C
A Foo is categorized by one FooType
A Bar is either one A or one C
A Bar is classified by one BarType
逻辑模型
然后,生成的IDEF1X [1]逻辑模型如图1所示(您也可以从Dropbox以PDF格式下载它):
Foo和Bar加法
我没加Foo
,并Bar
更好地使模型的样子,而是使之更具表现力。我认为由于以下原因,它们很重要:
但是,这些只是假设,并且由于关系数据库旨在准确反映特定业务上下文的语义,因此您必须在特定领域中对所有感兴趣的事物进行识别和分类,以便您可以准确地捕获更多含义。
设计阶段的重要因素
意识到以下事实是非常有用的:撇开所有术语,排他的超型-亚型群集是普通关系。让我们以以下方式描述情况:
- 每个排他上位实体类型出现都只与一个子实体类型补语相关。
因此,在这些情况下,存在一对一(1:1)的对应关系(或基数)。
从前面的帖子中可以知道,在创建具有这种性质的关联时,discriminator属性(在实现时为列)起着至关重要的作用,因为它指示了超类型所连接的正确子类型实例。主键从(i)超型向(ii)亚型的迁移也具有重要意义。
混凝土DDL结构
然后我写了一个基于上面介绍的逻辑模型的DDL结构:
CREATE TABLE FooType -- Look-up table.
(
FooTypeCode CHAR(2) NOT NULL,
Description CHAR(90) NOT NULL,
CreatedDateTime DATETIME NOT NULL,
CONSTRAINT PK_FooType PRIMARY KEY (FooTypeCode),
CONSTRAINT AK_FooType_Description UNIQUE (Description)
);
CREATE TABLE Foo -- Supertype
(
FooId INT NOT NULL, -- This PK migrates (1) to ‘Bar’ as ‘BarId’, (2) to ‘A’ as ‘AId’, (3) to ‘B’ as ‘BId’, and (4) to ‘C’ as ‘CId’.
FooTypeCode CHAR(2) NOT NULL, -- Discriminator column.
D INT NOT NULL, -- Column that applies to ‘Bar’ (and therefore to ‘A’ and ‘B’) and ‘C’.
CreatedDateTime DATETIME NOT NULL,
CONSTRAINT PK_Foo PRIMARY KEY (FooId),
CONSTRAINT FK_from_Foo_to_FooType FOREIGN KEY (FooTypeCode)
REFERENCES FooType (FooTypeCode)
);
CREATE TABLE BarType -- Look-up table.
(
BarTypeCode CHAR(1) NOT NULL,
Description CHAR(90) NOT NULL,
CONSTRAINT PK_BarType PRIMARY KEY (BarTypeCode),
CONSTRAINT AK_BarType_Description UNIQUE (Description)
);
CREATE TABLE Bar -- Subtype of ‘Foo’.
(
BarId INT NOT NULL, -- PK and FK.
BarTypeCode CHAR(1) NOT NULL, -- Discriminator column.
E INT NOT NULL, -- Column that applies to ‘A’ and ‘B’.
CONSTRAINT PK_Bar PRIMARY KEY (BarId),
CONSTRAINT FK_from_Bar_to_Foo FOREIGN KEY (BarId)
REFERENCES Foo (FooId),
CONSTRAINT FK_from_Bar_to_BarType FOREIGN KEY (BarTypeCode)
REFERENCES BarType (BarTypeCode)
);
CREATE TABLE A -- Subtype of ‘Bar’.
(
AId INT NOT NULL, -- PK and FK.
X INT NOT NULL, -- Particular column.
CONSTRAINT PK_A PRIMARY KEY (AId),
CONSTRAINT FK_from_A_to_Bar FOREIGN KEY (AId)
REFERENCES Bar (BarId)
);
CREATE TABLE B -- (1) Subtype of ‘Bar’ and (2) supertype of ‘A’ and ‘B’.
(
BId INT NOT NULL, -- PK and FK.
Y INT NOT NULL, -- Particular column.
CONSTRAINT PK_B PRIMARY KEY (BId),
CONSTRAINT FK_from_B_to_Bar FOREIGN KEY (BId)
REFERENCES Bar (BarId)
);
CREATE TABLE C -- Subtype of ‘Foo’.
(
CId INT NOT NULL, -- PK and FK.
Z INT NOT NULL, -- Particular column.
CONSTRAINT PK_C PRIMARY KEY (CId),
CONSTRAINT FK_from_C_to_Foo FOREIGN KEY (FooId)
REFERENCES Foo (FooId)
);
使用这种结构,您可以避免在基表(或Relationships)中存储NULL标记,这会给数据库带来歧义。
完整性,一致性和其他注意事项
实现数据库后,必须确保(a)每个排他超类型行始终由其对应的子类型对应项补充,并相应地确保(b)此类子类型行与超类型区分符列中包含的值兼容。因此,使用ACID TRANSACTIONS
来确保在数据库中满足这些条件是非常方便的。
您不应该放弃数据库的逻辑健全性,自我表达能力和准确性,而这些方面绝对可以使您的数据库更加牢固。
先前发布的两个答案已经包含了相关的观点,在设计,创建和管理数据库及其应用程序时肯定值得考虑。
通过VIEW定义检索数据
您可以设置一些视图,以合并不同超类型-子类型组的列,以便可以检索手头的数据,而无需每次例如编写必要的JOIN子句。这样,您可以轻松地直接从感兴趣的VIEW(派生关系或表)中进行选择。
如您所见,毫无疑问,“泰德·科德”是个天才。他遗赠的工具非常强大,优雅,而且彼此之间的集成度很高。
相关资源
如果您要分析一些涉及超类型-子类型关系的扩展数据库,您会发现@PerformanceDBA针对以下堆栈溢出问题提出的非凡答案非常有价值:
注意
1. 信息建模集成定义(IDEF1X)是一种高度推荐的数据建模技术,它是由美国国家标准技术研究院(NIST)于1993年12月建立为标准的。它牢固地基于(a) EF Codd博士撰写的早期理论材料;上(b)中的实体关系数据,通过开发的视图PP五福 ; 以及(c) Robert G. Brown创建的逻辑数据库设计技术。值得注意的是,IDEF1X是通过一阶逻辑形式化的。