多列外键约束

时间:2010-12-23 15:51:52

标签: sql sql-server-2005 database-design constraints foreign-key-relationship

我想为以下场景设置表约束,我不确定如何操作,或者甚至可以在SQL Server 2005中使用。

我有三张桌子A,B,C。 C是B的子级.B将有一个可选的外键(可能为null)引用A.出于性能原因,我还希望表C对表A具有相同的外键引用。表C上的约束应该是C必须引用其父级(B),并且还具有与其父级相同的外键引用。

有人对如何做到这一点有任何想法吗?

5 个答案:

答案 0 :(得分:5)

我认为没有必要明确强制执行从C到A的关系。只需按照从C到B到A的链。

答案 1 :(得分:2)

一般来说,我没有看到这样做的具体原因 - 但是,你确实问过。

要理解的是,关系模型不必遵循OO模型。 这是呈现Customer-Order-LineItem的标准方式。没错。

alt text

如果我想查找属于客户的所有订单项,我必须通过Order表加入,类似于OO点符号(Customer.Order.LineItem)。

select * 
from Customer as c
join Order    as o on o.CustomerId = c.CustomerId
join LineItem as i on i.OrderId    = o.OrderId
where CustomerID = 7 ;

假设我稍微修改了一下键,比如:

alt text

CustomerOrderId是每个客户的订单序号(1,2,3 ......),CustomerOrderItemId是每个客户订单的订单项序号(1, 2,3 ...)。每个都很容易生成,如

-- next CustomerOrderId
select coalesce(max(CustomerOrderId), 0) + 1
from  Order
where CustomerId = specific_customer_id;

-- next CustomerOrderItemId
select coalesce(max(CustomerOrderItemId), 0) + 1
from  LineItem
where CustomerId      = specific_customer_id
  and CustomerOrderId = specific_customer_order_id;

现在,如果我想查找属于客户的行项目(以及一些客户数据),我可以跳过Order表。

select * 
from Customer as c
join LineItem as i on i.CustomerId = c.CustomerId
where CustomerID = 7 ;

如果我不需要Customer表中的任何特定数据,则根本不需要加入。将此与第一个示例进行比较 - 请记住,获取行项目是目标。

select * 
from LineItem
where CustomerID = 7 ;

因此,对于关系模型,通过传播(自然)键,您不必总是“在连接中沿着关系路径停在每个站点”。

哪个更好?取决于你问谁。

希望您能够将基本原则转化为您的示例 - 我发现很难使用泛型(A,B,C)。

答案 2 :(得分:1)

用于提高性能的非规范化非常常见,特别是如果您有证据显示其价值。我认为你有充分的理由这样做,所以我不会解决这个问题。

您是否想过在C上设置一个插入触发器,它根据表B中的查找设置引用表A的列?您可能还需要在C和B上更新触发器以确保它始终保持同步。这将确保表C中引用表A的列始终是正确的,即使它没有被实际约束“强制执行”。

答案 3 :(得分:0)

  

我有三张桌子A,B,C。 C是一个   B. B的孩子将有一个可选的   外键(可以为null)引用   答:出于性能原因,我也想要   表C具有相同的外键   参考表A.约束   在表C上应该是C必须的   引用其父母(B)也有   与A相同的外键引用   它的父母。

你可以让表B有一个双主键(A的键,然后说一个标识),然后用它来链接到C.这不允许你在B上有一个空的外键引用,但是外键不允许为null。

真的如果你已经设置了正确的索引等,就没有真正需要将A的键推到C.将它连接到表B以获得A的键不会有太大的性能损失(几乎没有)。

答案 4 :(得分:0)

看起来常见的情况是你有A的密钥而你需要C中所有匹配的行。在这种情况下,下面的查询应该很快:

select C.* 
from B
join C on C.Bid = B.Bid
where C.Aid = <value>

使用适当的索引,这应该与在C上使用Aid一样快,因为它们都需要索引扫描,然后将结果连接到C表。