多列外键约束

发布于 2024-10-09 10:27:30 字数 215 浏览 4 评论 0原文

我想为以下场景设置表约束,但我不确定如何做到这一点,或者在 SQL Server 2005 中是否可能。

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

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

I want to setup table constraints for the following scenario and I’m not sure how to do it or if it’s even possible in SQL Server 2005.

I have three tables A,B,C. C is a child of B. B will have a optional foreign key(may be null) referencing A. For performance reasons I also want table C to have the same foreign key reference to table A. The constraint on table C should be that C must reference its parent (B) and also have the same foreign key reference to A as its parent.

Anyone have any thoughts on how to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

來不及說愛妳 2024-10-16 10:27:30

我认为没有必要明确强制从 C 到 A 的关系。只需遵循从 C 到 B 再到 A 的链条即可。

I don't see a need to explicitly enforce the relationship from C to A. Simply follow the chain from C to B to A.

南七夏 2024-10-16 10:27:30

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

需要理解的是,关系模型不必遵循 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)很难。

In general I do not see a specific reason to do this -- however, you did ask.

Thing to understand is that a relational model does not have to follow an OO model.
This is a standard way to present Customer-Order-LineItem. Nothing wrong with this.

alt text

If I want to find all line-items belonging to a customer, I have to join via the Order table, similar to the OO dot-dot notation (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 ;

Suppose that I modify keys a bit, like:

alt text

The CustomerOrderId is an order sequence number for each customer (1,2,3 ...) and the CustomerOrderItemId is a line-item sequence number for each of the customer's orders (1,2,3 ...). Each one is easy to generate, as in

-- 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;

Now if I want to find line-items belonging to a customer (and some customer data), I can skip the Order table.

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

And If I do not need any specific data from the Customer table, no need to join at all. Compare this to the first example -- remember that getting line-items was the objective.

select * 
from LineItem
where CustomerID = 7 ;

So, with the relational model, by propagating (natural) keys, you do not have to always "stop at each station along a relationship path" in joins.

Which is better? Depends who you ask.

Hope you will be able to translate the underlying principle into your example -- I find it hard to work with generic (A,B,C).

烟酒忠诚 2024-10-16 10:27:30

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

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

Denormalization for the purposes of improving performance is pretty common, especially if you have evidence showing its value. I assume you have good reasons for doing so, so I won't address that.

Have you thought of simply having an insert trigger on C which sets the column referencing table A based on a lookup in table B? You may also need update triggers on C and B to ensure it is always in sync. This would ensure the column in table C which references table A is always correct, even if it isn't "enforced" by an actual constraint.

朕就是辣么酷 2024-10-16 10:27:30

我有三个表 A、B、C。 C是一个
B. B 的孩子将有一个可选的
外键(可能为空)引用
A.出于性能原因我也想要
表 C 具有相同的外键
参考表A。约束
表 C 上应该是 C 必须
引用其父级 (B) 并且还有
对 A 的相同外键引用
它的父级。

您可以让表 B 有一个双主键(A 的键,然后说一个身份),然后使用它链接到 C。虽然这不允许您在 B 上有一个空外键引用,但是外键无论如何都不允许为空。

实际上,如果您正确设置了索引等,则不需要将 A 的密钥推送到 C。将其连接到表 B 以获取 A 的密钥不会对性能造成太大影响(几乎没有)。

I have three tables A,B,C. C is a
child of B. B will have a optional
foreign key(may be null) referencing
A. For performance reasons I also want
table C to have the same foreign key
reference to table A. The constraint
on table C should be that C must
reference its parent (B) and also have
the same foreign key reference to A as
its parent.

You can have table B have a dual primary key (A's key, and then say an identity), and then use that to link to C. This won't allow you to have a null foreign key reference on B though, but foreign keys aren't allowed to be null anyway.

Really if you have indexes etc. set properly, there isn't a real need to push A's key to C. Joining it to table B to get A's key won't be that much of a performance hit (like almost none).

假装爱人 2024-10-16 10:27:30

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

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

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

Looks like the common ues case for you is you have A's key and you need all the matching rows in C. In which case the following query should be fast:

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

with proper indexes this should be just as fast as if you have Aid on C because they will both require an index scan followed by joining that result to the C table.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文