2009-09-11 38 views
2

我有一个需要链接三个独立表中的一个表的表,但它只能链接到其中的一个表,例如,是否可以约束一个表只有一组列中的一个值

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)。

这是我继承的数据库设计,不幸的是它并不真正改变。

我最大的问题是我需要关联不同的类型,所以类型字段不会在这里工作,因为索引是不同的。

+0

它气味不好的设计。你可以更多地了解数据是什么以及为什么你想以这种方式来关联它? – spender 2009-09-11 01:25:57

+0

看起来你试图创建某种有条件的外键。正如提到的那样,对你想要完成的事情的感觉将帮助我们确定最佳方法。 – 2009-09-11 01:30:15

回答

4

你所描述的被称为独家弧设计。是的,这是一个非常脆弱的设计,甚至没有规范化的规则。

这里有一个选择:

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中的每一行可以是T1T2T3中仅有一行的父代。

这是一种实现类表继承和多态关联而不破坏参照完整性的方法。


MAIN_TABLE试图是付款人 表,该表可能会参照任一种 单个用户(T1),一组 单个用户(T2)的,或一组 基(T3) 。

对,所以在面向对象的设计方面想一想。如果您有三个可用作付款收款人的班级,您可以创建一个界面或称为Payable,这样您就可以依靠输入这些对象。例如,所有Payable对象都必须具有sendPayment()方法。在某些OO语言中,接口是超类,称为抽象类纯虚拟类

T0表作为每个子表T1T2T3的通用类型。当Main_Table有一个到T0的外键,就像是说Main_Table必须对某个实体的引用是Payable,但是任何从该超类下降的对象都可以使用。

type列只是确保给定的T0.id一次只能由一个子类表引用的技巧。如果你可以依靠你的应用程序逻辑将一个给定的子行插入到其中一个子类表中,那么它是可选的。


也看到在我的演讲多态关联节 “SQL Antipatterns Strike Back。”

+0

我不明白为什么在这个例子中T0是必要的?这并不能解决不同类型的按键问题。我在这里错过了什么吗? – Khanzor 2009-09-11 02:07:14

+0

@ Bill:这是一个很棒的演示。我想我只需要使用代理来处理用不同的密钥来查找信息。谢谢您的帮助! – Khanzor 2009-09-11 04:00:01

+0

@Bill漂亮的演示! – 2011-10-14 21:54:12

0

除了糟糕的设计,如果你不能改变它,它可能使用触发器来加强这个约束

1

如果您的数据库有检查约束,你可以掀起一个丑陋的杂牌组装电脑一样:

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非常酷,如果你可以重新设计数据库设计。

0

这是gen-spec模式的另一个实例。

请转到关于“泛化专业化关系建模”的网页文章。有一些优秀的那里。

相关问题