将外键用作主键可以吗?


102

我有两个表:

  • 用户(用户名,密码)
  • 个人资料(个人资料ID,性别,出生日期等)

当前,我正在使用这种方法:每个Profile记录都有一个名为“ userId”的字段作为外键,该字段链接到User表。用户注册后,将自动创建其个人资料记录。

我很困惑与我的朋友建议:有“用户id”字段作为外国键和删除“简档”字段。哪种方法更好?


3
实体框架为零或一(和一对一)一对一关系生成代码(首先生成代码)。所以...有可能。这是最好的方法吗?这是另一个问题。但这是有效的。我在创建自己的数据库时从未这样做(但我什至从未想到过)。
拉斐尔Althaus

Answers:


132

外键几乎总是“允许重复”,这会使它们不适合用作主键。

而是,找到一个唯一标识表中每个记录的字段,或者添加一个新字段(自动递增的整数或GUID)作为主键。

唯一的例外是具有一对一关系的表,其中链接表的键和键是相同的。


73
由两个外键组成的复合主键也非常适合实现多对多关系。
2014年

1
@rezadru:完全不同意我的观点,但是代理键几乎总是一个更好的选择。
罗伯特·哈维

4
关于外键的任何规定都不能表明它是一对多的(或书面上的“允许重复”)。关键约束和唯一性是数据库中的两个独立概念,可以像添加索引一样轻松地混合(这将是第三个独立概念)。
盲人

40

如果表是一对多关系,则主键始终需要唯一,外键必须允许非唯一值。如果表是通过一对一关系而不是一对多关系连接的,则将外键用作主键是完全可以的。如果您希望同一个用户记录具有多个相关的个人档案记录,请使用单独的主键,否则请坚持使用您拥有的主键。


11

是的,将主键作为外键是合法的。这是一种罕见的构造,但适用于:

  • 1:1关系。这两个表不能合并为一个表,因为不同的权限和特权仅适用于表级别(从2017年开始,这样的数据库很奇怪)。

  • 1:0..1关系。配置文件可能存在或不存在,具体取决于用户类型。

  • 性能是一个问题,设计是一个分区:与用户表相比,概要文件表很少被访问,位于单独的磁盘上或具有不同的分片策略。如果下划线存储是柱状的,则没有任何意义。


如果经常将表连接在一起,将会产生负面的影响,这通常导致建议最好使用1个表。在某些情况下,总是分开访问数据而不是将其合并,并且拥有两个具有1:1关系的表可能会给组织带来好处。
盲人

4

建立一对一关系通常被认为是不好的做法。这是因为您可以只将数据表示在一个表中并获得相同的结果。

但是,在某些情况下,您可能无法对要引用的表进行这些更改。在这种情况下,使用外键作为主键没有问题。拥有一个由自动递增的唯一主键和外键组成的复合键可能会有所帮助。

我目前正在使用一个系统,用户可以在该系统上登录并生成用于应用程序的注册码。由于某些原因,我将不进行介绍,因此我无法简单地将所需的列添加到users表。所以我要沿着代码表进行一对一的选择。


2
我主要同意您的观点,将所有数据与其他列放在同一表中具有许多优点。尽管这样。.“您可以只将数据表示在一个表中并获得相同的结果” ..:具有单独的表可能很有用,例如,在这里配置文件表项是可选的。例如,每个银行客户可能没有互联网银行注册。在这种情况下,IB注册表可用于限制其他表具有其他子记录。同样,这里也可以使用IB注册表的新PK来完成。
泰迪

1
@Teddy同样,我大体上同意你所说的。但是,在原始问题中,他们指出“ ...他的个人档案记录已自动创建...”,这意味着个人档案表不是可选的。在配置文件表是可选的情况下,则可以将其作为单独的表来进行。但是话又说回来,他们只能在同一张表中使用可为空的列。
Tshsmith '17

1
使用单独的第二张表,我们可以防止在第三张表中输入,只有在第二张表中有输入的人才可以输入第三张表。
泰迪

绝对可以,但是如果我们合并1到1的表,我们可以防止具有空值的人访问第三个表(技术上现在是第二个)。但是OP提出的问题包含“ ...在注册时.....他的个人资料记录会自动创建...”这一行,这使其变得多余。
Tshsmith '17

考虑这一点的主要原因是,在数据仓库中,将事实表和维表分开是一个好习惯。当使用诸如PowerPivot,PowerBI和Tableau之类的软件时,单独的事实和维度表是有用的提示。
Marco Rosas

4

是的,在这些表之间一对一的关系中,外键可以是主键


2
这对于超类型-子类型设计也很有用。子类型表的主键应该是对父类型表的外键引用。
axelioo

2

我不会那样做。我将保留profileID表的主键Profile

外键只是两个表之间的引用约束

可能有人争辩说,主键是作为从其他表引用它的任何外键的目标所必需的。外键是任何表中一个或多个列的集合(不一定是该表的候选键,更不用说主键了),它可以保存某些表的主键列中的值。其他表。所以我们必须有一个主键来匹配外键。还是必须?主键/外键对中主键的唯一目的是提供明确的连接-相对于保存引用的主键的“外”表保持引用完整性。这样可以确保外键引用的值将始终有效(如果允许,则为null)。

http://www.aisintl.com/case/primary_and_foreign_key.html


1
也许-如果您在User.UserID和Profile.UserID之间具有FK约束,则强烈建议在Profile.UserID上具有索引。为什么不在表Profile上创建主聚集索引,为数据库引擎节省第二个索引和大量不必要的工作呢?
工程师

1

这取决于业务和系统。

如果您的userId是唯一的并且将一直都是唯一的,则可以将userId用作主键。但是,如果您想扩展您的系统,那将使事情变得困难。我建议您在表用户中添加外键以与表概要文件建立关系,而不是在表概要文件中添加外键。


0

简短答案:取决于...。在这种情况下,可能会很好。但是,专家几乎每次都会建议这样做。包括你的案子

为什么?

当键在所讨论的表中是外来键(起源于另一个表)时,表中的键很少是唯一的。例如,一个项目ID在ITEMS表中可能是唯一的,但在ORDERS表中可能不是唯一的,因为相同类型的项目很可能会以另一顺序存在。同样,订单ID在ORDERS表中可能是唯一的(可能),但在ORDER_DETAILS之类的其他表中可能不是唯一的,在该表中可以存在具有多个订单项的订单,并且要查询特定订单中的特定项目,您需要将两个FK(order_id和item_id)作为此表的PK。

我不是数据库专家,但是如果您可以合理地证明有一个自动生成的值作为PK,我会这样做。如果这不切实际,则两个(或更多)FK的串联可以用作您的PK。但是,我无法想到可以将单个FK值证明为PK的任何情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.