【问题标题】:Should a foreign key be created on the parent table or child table?应该在父表还是子表上创建外键?
【发布时间】:2013-02-21 17:34:20
【问题描述】:

有什么区别?如果我有这两个表:

CREATE TABLE Account (Id int NOT NULL)

CREATE TABLE Customer (AccountId int NOT NULL)

我想要一个外键链接两者,我应该做以下哪一个?为什么?

选项 1:

ALTER TABLE [dbo].[Customer]  WITH CHECK 
  ADD  CONSTRAINT [FK_Accounts_Customers] FOREIGN KEY([AccountId])
  REFERENCES [dbo].[Account] ([Id])

选项 2:

ALTER TABLE [dbo].[Account]  WITH CHECK 
  ADD  CONSTRAINT [FK_Accounts_Customers] FOREIGN KEY([Id])
  REFERENCES [dbo].[Customer] ([Id])

【问题讨论】:

  • 我通常把它放在一张没有另一张的桌子上(如果适用)。但这将取决于使您的查询更简单的方法,从数据概念的角度来看更有意义的方法……甚至这两个可能是相反的。

标签: sql sql-server-2008-r2 foreign-keys


【解决方案1】:

取决于上下文。每个客户都有客户吗?哪个是家长?似乎一个帐户有多个客户,在这种情况下,引用属于客户表。

现在,也就是说,请在任何地方致电实体CustomerIDAccountID。它在主表上可能看起来多余,但名称应该在整个模型中保持一致。

【讨论】:

  • 关于命名的百分之一的同意。您不应该使用 ID 作为 PK 的字段名称 - 始终以实体名称作为前缀。这在使用使用基于约定的映射的 ORM 时尤其重要,因为这通常是他们期望模型的外观。缺点是你必须在编写连接时限定你的对象,但是a) 你无论如何都应该这样做,b) 使用 ORM 你可能不会写太多/任何 T-SQL
  • 如果您使用 Rails 和受 Rails 启发的框架,那是不正确的。在那种情况下,当 id 是主键时,它只是像customers.id 这样的“id”——这很明显。当被引用为 foreign_key 时,你会这样做 accounts.customer_id 像这样。
【解决方案2】:

我会使用从孩子到父母的外键。最典型的问题是:如果您需要删除其中一个实体会发生什么?

【讨论】:

  • 在这种情况下,如果我删除一个客户,我不希望它级联到帐户,但如果我删除一个帐户,它应该级联到客户。
  • 所以帐户可以没有客户但客户不能有帐户。因此,客户应该指出帐户,而不是相反。 --> 选项 1
  • @scottm 您应该在处理级联的 DELETE 过程中编写逻辑。我不是 SQL Server 中当前可用的 ON CASCADE 选项的忠实粉丝,也不太信任。
【解决方案3】:

FK(外键)告诉 DBMS,列列表的子行值必须作为列列表的子行值出现在别处。每当发生这种情况(并且其他声明尚未暗示)时,声明 FK。此外,如果您希望在更改引用表时将 CASCADE 操作应用于被引用表,请声明。

(CASCADE 没有什么特别之处在于它不能用于非 FK 的情况。它只是经常与 FK 一起出现,并且有一个明确的 FK 图可以合理地限制它们的交互。)

如果有FK cycle,那么您将需要使用触发器。您决定哪些约束是声明式强制执行的,哪些是触发器应该考虑(期望的)约束图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-20
    • 1970-01-01
    • 2011-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多