介绍
为了让这个问题对未来的读者有用,我将使用通用数据模型来说明我面临的问题。
我们的数据模型由两个实体组成,应标记为A
和B
。为了简单起见,它们的所有属性都是int
类型的。
实体A
具有以下属性:D
和X
;实体B
具有以下属性:D
和Y
;
问题
由于两个实体共享共同属性D
,我决定应用类型/子类型设计。
我不确定我的实施是否正确,因此我在这里要求进行设计审查。
我的实现
-- lookup table for discriminator column
CREATE TABLE ClassType
(
ClassTypeID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
Class_Description VARCHAR(50) NOT NULL
);
-- inserting types A and B from our example
INSERT INTO ClassType (Class_Description)
VALUES ('A'), ('B');
-- creating base class table
CREATE TABLE BaseClass
(
BaseClass_ID INT NOT NULL IDENTITY(1, 1) PRIMARY KEY,
ClassTypeID INT NOT NULL, -- FK to Type
D int
);
ALTER TABLE BaseClass
ADD CONSTRAINT [FK_BaseClass_ClassType]
FOREIGN KEY (ClassTypeID)
REFERENCES ClassType (ClassTypeID);
-- we need this constraint in order for foreign keys in subclasses to work
ALTER TABLE BaseClass
ADD CONSTRAINT [FK_AltKey]
UNIQUE (BaseClass_ID, ClassTypeID);
-- creating subclasses:
CREATE TABLE SubclassA
(
BaseClass_ID INT NOT NULL PRIMARY KEY,
X int,
ClassTypeID AS 1 PERSISTED -- calculated field, ensures integrity
);
ALTER TABLE SubclassA
ADD CONSTRAINT [FK_SubclassA_BaseClass]
FOREIGN KEY (BaseClass_ID, ClassTypeID)
REFERENCES BaseClass (BaseClass_ID, ClassTypeID);
CREATE TABLE SubclassB
(
BaseClass_ID INT NOT NULL PRIMARY KEY,
Y int,
ClassTypeID AS 2 PERSISTED -- calculated field, ensures integrity
);
ALTER TABLE SubclassB
ADD CONSTRAINT [FK_SubclassB_BaseClass]
FOREIGN KEY (BaseClass_ID, ClassTypeID)
REFERENCES BaseClass (BaseClass_ID, ClassTypeID);
这是数据库图表在 SQL Server 2012 中的样子:
问题
- 我在实施过程中犯了什么错误吗?
- 除了计算和持久化类类型(在子类表中)之外,还有什么我可以做的来防止错误发生
INSERT/UPDATE/DELETE
吗?
是的,设计看起来很棒。次要注意事项:
您可以使用
TINYINT
, 而不是INT
for theClassTypeID
。甚至CHAR(1)
用'A'
and'B'
代替1
and2
。1 字节而不是 4 意味着您在每一行、所有 3 个表和包含的每个索引中保存 3 个字节——如果是聚集键的一部分,ClassTypeID
这将是这些表上的每个索引。ClassTypeID
基表和子类型表的属性都可以是
NOT NULL
. 我不明白为什么您希望使用这种设计它们可以为空。UNIQUE
如果您同时拥有基表的约束和引用它的 2 个外键,它可能会更好(但需要彻底测试)定义为 reverse order(ClassTypeID, BaseClass_ID)
。这更像是一个索引/物理设计建议,它不会改变逻辑设计。我也会尝试使用此顺序在基表中添加聚簇键。