是否可以将表限制为仅在一组列中的一列中具有值
-
05-07-2019 - |
题
我有一个表需要链接三个单独的表中的一个,但它只应链接到其中一个,例如。
Main_Table
id UNIQUEIDENTIFIER
t1_id UNIQUEIDENTIFIER
t2_id INT
t3_id INT
T1
id UNIQUEIDENTIFIER
name VARCHAR(255)
T2
id INT
name VARCHAR(255)
T3
id INT
name VARCHAR(255)
是否有可能有一个约束,即t1,t2或t3中的任何一个在任何时候都不为空?
这只是糟糕的设计吗?如果是这样,你会对设计提出什么建议?
修改强>
我被要求详细说明这种特殊设计背后的原因。
Main_Table试图成为付款人表,可以引用单个用户(T1),一组个人用户(T2)或一组组(T3)。
这是我继承的数据库设计,不幸的是它实际上不会发生变化。
我最大的问题是我需要在不同类型之间关联,因此类型字段在这里不起作用,因为索引不同。
解决方案
您所描述的设计称为独占弧。是的,这是一个非常脆弱的设计,甚至没有一些规范化规则。
这是另一种选择:
Main_Table
id UNIQUEIDENTIFIER
t_id INT NOT NULL
FOREIGN KEY (t_id) REFERENCES T0 (id)
T0
id UNIQUEIDENTIFIER
type INT NOT NULL CHECK (type IN (1,2,3))
UNIQUE KEY (id, type)
T1
id INT
type INT NOT NULL CHECK (type = 1)
name VARCHAR(255)
FOREIGN KEY (id, type) REFERENCES T0 (id, type)
T2
id INT
type INT NOT NULL CHECK (type = 2)
name VARCHAR(255)
FOREIGN KEY (id, type) REFERENCES T0 (id, type)
T3
id INT
type INT NOT NULL CHECK (type = 3)
name VARCHAR(255)
FOREIGN KEY (id, type) REFERENCES T0 (id, type)
使用此设计, Main_Table
中的每一行必须引用 T0
中的一行。
同样, T0
中的每一行都可以是 T1
, T2
或 T3
中只有一行的父级。
这是一种在不破坏参照完整性的情况下实现类表继承和多态关联的方法。
Main_Table正试图成为付款人 表,可以引用任何一个 个人用户(T1),一组 个人用户(T2),或一组 团体(T3)。
是的,所以在面向对象设计方面要考虑到这一点。如果您有三个可以充当付款接收者的类,您可以创建一个名为 Payable
的接口,这样您就可以依赖于键入这些对象。例如,所有 Payable
对象必须具有 sendPayment()
方法。在某些OO语言中,接口是一个超类,称为抽象类或纯虚拟类。
T0
表用作每个子表 T1
, T2
和 T3
。当 Main_Table
具有 T0
的外键时,就像说 Main_Table
必须引用某个 Payable
,但是从该超类下降的任何对象都可以使用。
type
列只是一个技巧,可以确保一次只能由一个子类表引用给定的 T0.id
。如果你可以依赖你的应用程序逻辑将一个给定的子行插入到一个子类表中,那么它是可选的。
另请参阅我的演示文稿中的多态关联部分" SQL Antipatterns Strike Back 。”
其他提示
如果你的数据库有检查限制,你可以掀起一个丑陋的kludge,如:
ALTER TABLE Main_Table
add constraint CK_ThisWorksButItsUgly
check ( ( case when t1_id is null then 0 else 1 end
+ case when t2_id is null then 0 else 1 end
+ case when t3_id is null then 0 else 1 end) = 1)
那里的一些语法可能有误,但你明白了。它可能表现得还不错 - 只有在其中一个列被修改后才能触发检查 - 但是没办法它很漂亮。
Bill Karwin的Exlusive Arcs非常酷,如果你可以重新设计数据库设计。
除了糟糕的设计,如果你不能改变它,可以使用触发器来强制执行这种约束
这是gen-spec模式的另一个例子。
关于“泛化专业化关系建模”的Google网络文章。那里有一些很棒的。