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

时间:2010-04-12 23:47:36

标签: database-design relational-database primary-key ddl database-table

这个例子是from 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)代表表Persons的主键。这是对的吗?

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

9 个答案:

答案 0 :(得分:109)

您的理解是正确的。

在很多情况下你会这样做。一个例子是OrderHeaderOrderDetail之类的关系。 OrderHeader中的PK可能是OrderNumberOrderDetail中的PK可能是OrderNumberLineNumber。如果它是这两者中的任何一个,它将不是唯一的,但两者的组合保证是唯一的。

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

答案 1 :(得分:23)

复合主键的另一个示例是关联表的使用。假设您有一个包含一组人员的人员表和一个包含一组组的组表。现在,您希望在人员和组上创建多对多关系。意味着每个人都可以属于许多群体。以下是使用复合主键的表结构。

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

答案 2 :(得分:9)

W3Schools示例并未说明何时应使用复合主键,并且仅使用与其他键相同的示例表提供示例语法。

他们选择的例子可能会通过组合无意义的密钥(P_Id)和自然密钥(LastName)来误导您。这种奇怪的主键选择表明以下行根据模式有效,并且是唯一标识学生所必需的。直觉上这没有意义。

1234     Jobs
1234     Gates

进一步阅读:The great primary-key debate或只是Google meaningless primary keys,或者甚至仔细阅读SO question

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

答案 3 :(得分:3)

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

答案 4 :(得分:2)

是的,它们都是主键。特别是在没有surrogate key的表中,可能需要指定多个属性作为每个记录的唯一标识符(错误示例:具有名字和姓氏的表可能需要组合它们是独一无二的。)

答案 5 :(得分:2)

密钥中的多个列通常比代理键执行得更差。我更喜欢使用代理键,然后在多列键上使用唯一索引。这样,您可以获得更好的性能,并保持所需的唯一性。更好的是,当该键中的一个值发生变化时,您不必更新215个子表中的一百万个子条目。

答案 6 :(得分:2)

你的第二个问题

  

在给定表中可以将多少列一起用作主键?

是特定于实现的:它在正在使用的实际DBMS中定义。 [1],[2],[3] 你必须检查数据库系统的技术规范你使用。有些非常详细,有些则不是。在网上搜索这些限制可能很难,因为术语各不相同。术语复合主键应该是必需的;)

如果找不到显式信息,请尝试创建测试数据库,以确保您可以期望稳定(和特定)处理限制违规(这是预期的)。请小心获取有关此信息的正确信息:有时会累积限制,并且您会看到不同数据库布局的不同结果。

答案 7 :(得分:1)

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

我将使用我曾经为一个例子制作的数据库,特别是该表中的三个表。几年前我创建了一个webcomic数据库。一张桌子被称为“漫画” - 所有漫画,其标题,图像文件名等的列表。主要键是“comicnum”。

第二张桌子是“人物” - 他们的名字和简短说明。主键是“charname”。

由于每个漫画 - 有一些例外 - 有多个角色,每个角色都出现在多个漫画中,因此将一列放在“角色”或“漫画”中以反映这一点是不切实际的。相反,我创建了第三个表被称为“漫画家”,这是一个列表,其中出现了漫画中的角色。由于这个表基本上连接了两个表,它只需要两列:charname和comicnum,主键都在两个列上。

答案 8 :(得分:0)

我们创建复合主键以保证组成单个记录的唯一性列值。这是一个约束,有助于防止插入不应重复的数据。

i.e:如果所有学生ID和出生证明号都唯一地分配给一个人。然后,使一个人的主键由学生证和出生证号码组成是一个好主意,因为这样可以防止您意外插入两个具有不同学生证和相同出生证的人。