为什么使用多个列作为主键(复合主键)

这个例子来自w3schools 。

CREATE TABLE Persons ( P_Id int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName) ) 

我的理解是,两个列在一起( P_IdLastName )代表人员的主键。 它是否正确?

  • 为什么有人想使用多列作为主键而不是单列?
  • 多less列可以一起用作给定表中的主键?

你的理解是正确的。

你会在很多情况下做到这一点。 一个例子是像OrderHeaderOrderDetail这样的关系。 OrderHeader的PK可能是OrderNumberOrderDetail的PK可能是OrderNumberLineNumber 。 如果这两者中的任何一个都不是唯一的,但两者的结合是唯一的。

另一种方法是使用生成的(非智能的)主键,例如在这种情况下OrderDetailId 。 但是,你不会总是很容易地看到这种关系。 有些人喜欢一种方式; 有些更喜欢另一种方式。

复合主键的另一个例子是关联表的使用。 假设你有一个包含一组人员的人员表格和一个包含一组组的表格。 现在你想创build一个人与群组之间的多对多关系。 意思是每个人都可以属于许多群体。 以下是使用复合主键的表结构。

 Create Table Person( PersonID int Not Null, FirstName varchar(50), LastName varchar(50), Constraint PK_Person PRIMARY KEY (PersonID)) Create Table Group ( GroupId int Not Null, GroupName varchar(50), Constraint PK_Group PRIMARY KEY (GroupId)) Create Table GroupMember ( GroupId int Not Null, PersonId int Not Null, CONSTRAINT FK_GroupMember_Group FOREIGN KEY (GroupId) References Group(GroupId), CONSTRAINT FK_GroupMember_Person FOREIGN KEY (PersonId) References Person(PersonId), CONSTRAINT PK_GroupMember PRIMARY KEY (GroupId, PersonID)) 

W3School的例子并不是说什么时候应该使用复合主键,而只是给出使用与其他键相同的示例表的示例语法。

他们的例子的select可能会误导你通过结合一个无意义的关键(P_Id)和一个自然键(LastName)。 主键的这种奇怪的select表明,根据模式,以下行是有效的,并且是唯一标识学生的必要条件。 直觉上这是没有意义的。

 1234 Jobs 1234 Gates 

进一步阅读: 伟大的主要关键辩论或只是谷歌meaningless primary keys ,甚至仔细阅读这个问题

FWIW – 我的2美分是为了避免多列主键,并使用一个生成的id字段(代理键)作为主键,并在必要时添加额外的(唯一的)约束。

只要您想确保多个属性组合的唯一性,就可以使用复合键(具有多个属性的键)。 一个属性键不会达到同样的效果。

你的第二部分问题

多less列可以一起用作给定表中的主键?

是特定于实现的:它是在实际使用的DBMS中定义的。 [1],[2],[3]您必须检查您使用的数据库系统的技术规格。 有些非常详细,有些不是。 在网上search这样的限制可能是困难的,因为术语各不相同。 术语复合主键应当是强制性的;)

如果您找不到明确的信息,请尝试使用testing数据库,以确保您可以预期稳定(和具体)处理违反限制(合理预期)的限制。 请小心获得有关此信息的正确信息:有时会限制积累,并且您将看到不同数据库布局的不同结果。


  • [1] sql – 复合主键限制? – 堆栈溢出
  • [2] SQL Server – 每个主键的最大列数
  • [3] 在Oracle 9i和10g的表中,主键的最大列数是多less?

是的,他们都是主要的关键。 特别是在没有代理键的表中,可能有必要指定多个属性作为每个logging的唯一标识符(例如:一个名字和姓氏的表可能需要它们的组合独特)。

一般而言,密钥中的多个列将比代理键执行得更差。 我更喜欢有一个代理键,然后在多列键上有一个唯一的索引。 这样你可以获得更好的性能,并保持所需的唯一性。 甚至更好的是,当该键中的某个值发生更改时,也不必更新215个子表中的一百万个子条目。

在关系数据库中使用中间表时,在多个表上使用主键会派上用场。

我将使用一个我曾经作过的例子,特别是在这个表格中的三个表。 我几年前创build了一个webcomic的数据库。 一张桌子被称为“漫画” – 所有漫画,他们的名称,图像文件名等的列表。主键是“漫画”。

第二张桌子是“人物” – 他们的名字和一个简短的描述。 主键是“charname”。

由于每个漫画(有些例外)都有多个angular色,每个angular色都出现在多个漫画中,所以在“angular色”或“漫画”中join一个栏目来反映这一点是不切实际的。 相反,我创造了第三张桌子被称为“漫画家”,这是一个列表中出现漫画的人物。 由于这个表本质上是join了两个表,所以它只需要两列:charname和comicnum,而且主键在两个列上。