如何正确创建复合主键-MYSQL


181

这是我正在使用的密集设置的过度简化。table_1table_2两者都具有自动增量的代理主键作为ID。info是包含有关table_1和的信息的表table_2

table_1 (id, field)  
table_2 (id, field, field)
info ( ???, field)

我试图决定,如果我应该做的主键info的复合ID的距离table_1table_2。如果我要这样做,哪一个最有意义?
(在此示例中,我将ID 11209与ID 437组合在一起)

INT(9)11209437 (我可以想象为什么这很糟糕)
VARCHAR (10) 11209-437
DECIMAL (10,4)11209.437

或者是其他东西?

将其用作MYSQL MYISAM DB上的主键是否可以?


Answers:


341

我会使用一个复合(多列)键。

CREATE TABLE INFO (
    t1ID INT,
    t2ID INT,
    PRIMARY KEY (t1ID, t2ID)
) 

这样,您还可以将t1ID和t2ID作为指向它们各自表的外键。


2
哇,这就是您制作复合键的方式!看起来我已经完全误解了这个概念。谢谢!!因此,这样的事情完全是为了建立索引才正确吗?因为在这种情况下我将无法引用记录,所以我还是必须这样做UPDATE info ... WHERE t1ID=11209 AND t2ID=437吗?
filip

2
正确。尽管由于两列都应该是唯一的,所以t1ID = 11209可能就足够了。
AlexCuse

39
@AlexCuse 两列的组合是唯一的,但是对于t1ID = 11209,可以有任意数量的t2ID。
e18r 2015年

21

我不会使“ info”表的主键成为其他表中两个值的组合。

其他人可以更好地阐明原因,但是拥有一个真正由两部分信息组成的专栏是不对的。如果出于某种原因要对第二张表的ID进行排序怎么办?如果要计算任一表中某个值出现的次数怎么办?

我将始终将它们保留为两个不同的列。您可以在mysql中使用两列素数键... PRIMARY KEY(id_a,id_b)...但我更喜欢使用两列唯一索引,并具有自动递增的主键字段。


1
保留不同的列绝对是正确的。我没有意识到您可能拥有两列唯一索引,但我认为这实际上对我来说是个不错的选择。我能问一下,为什么您还是希望保留主键为自动增量?
filip

3
我没有真正令人信服的理由,我承认这是我和一些同事之间的争论点,因为减少列数会更经济。我发现在单个外键上编写联接更容易。有时,这些表“两个表之间的映射”的重要性与原始表一样重要,并且其主键成为其他表中的外键列。
wmorse 2011年

谢谢。我认为您的说法很有道理,我将其作为两列唯一索引+自动递增主键进行尝试
filip

1
我想从我的头开始的原因是您想创建一个关系表。您有三个表,例如市场,货币和提供者,一个提供者只能存在于一个市场中,因此您的关系表只能提供一种货币,因此您将合成(id_market,id_provider),这意味着您只能一次该连接,再次尝试将同一市场和提供者加在一起,将失败,这意味着它们是唯一的,那么您将有第二列,即id_currency,这表示整个表中的货币是单数,这有意义吗?
Christopher Thomas

1
对于以后看到此线程的任何人,请注意,这是不好的做法,是因为它违反了数据库设计的非常基本的原则。第一范式要求每条信息都有其自己的列。几乎没有理由违反此规范,而且对标准化数据库结构也有很多好处。
smcjones

15

语法CONSTRAINT constraint_name PRIMARY KEY(col1,col2,col3)例如是::

CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)

如果您在创建表时编写该示例,则上面的示例将起作用:

CREATE TABLE person (
   P_Id int ,
   ............,
   ............,
   CONSTRAINT pk_PersonID PRIMARY KEY (P_Id,LastName)
);

将此约束添加到现有表中,您需要遵循以下语法

ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY (P_Id,LastName)


5

除了个人设计偏好外,在某些情况下,人们还想使用复合主键。表可以具有两个或多个字段,这些字段提供唯一的组合,而不必使用外键。

例如,美国每个州都有一套独特的国会区。尽管许多州可能单独拥有CD-5,但在这50个州中,任何一个州的CD-5都不会超过一个,反之亦然。因此,为马萨诸塞州CD-5创建一个自动编号字段将是多余的。

如果数据库驱动动态网页,则编写代码以在两字段组合上进行查询可能比提取/重新提交自动编号的密钥简单得多。

因此,虽然我没有回答原始问题,但我当然感谢亚当的直接回答。


4

复合主键是您想要在事实表中创建多对多关系的地方。例如,您可能有一个假期租赁套餐,其中包含许多属性。另一方面,该物业也可以单独或与其他物业一起作为许多租赁套餐的一部分使用。在这种情况下,您可以使用属性/包事实表在属性和租赁包之间建立关系。属性和包之间的关联将是唯一的,您将永远只能使用property_id和property表和/或package_id和package表一起加入。每个关系都是唯一的,并且auto_increment键是多余的,因为它不会在任何其他表中使用。因此,定义组合键就是答案。


1
CREATE  TABLE `mom`.`sec_subsection` (

  `idsec_sub` INT(11) NOT NULL ,

  `idSubSections` INT(11) NOT NULL ,

  PRIMARY KEY (`idsec_sub`, `idSubSections`) 

);

1

@AlexCuse我想将此添加为您的答案中的注释,但是在多次尝试在注释中添加换行符失败之后放弃了。

也就是说,t1ID在table_1中是唯一的,但在INFO表中也没有唯一。

例如:

表_1具有:
标识字段
1 A
2 B

表_2具有:
标识字段
1 X
2 Y

INFO然后可以具有:
t1ID t2ID字段
1 1一些
1 2数据
2 1每个in
2 2行

因此,在INFO表中以唯一地标识一行,您既需要t1ID又需要t2ID


它称为复合键
Pavel P

1
@PavelP我的答复是wrt Alex的评论“尽管两列都应该是唯一的,但t1ID = 11209可能就足够了。” ...我同意使用复合键是正确的,但是要确定完全匹配,您将同时需要t1ID和t2ID ...我希望现在已经清楚了。
sactiw
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.