MySQL 5中的多列主键

38

我正在学习如何使用键,并打破必须在所有表中的所有行都具有SERIAL类型ID的习惯。同时,我也在进行多对多关系,因此要求协调关系的表的任一列上的唯一值会妨碍它。

如何定义一个主键,使得任何给定值可以在任何列中重复出现,只要跨所有列的值的组合从来没有完全重复?


可能是如何正确创建复合主键 - MYSQL的重复问题。 - Ciro Santilli OurBigBook.com
2
不能成为三年后发布的某个内容的副本。 - Kaji
http://meta.stackexchange.com/questions/147643/should-i-vote-to-close-a-duplicate-question-even-though-its-much-newer-and-ha ;-)(注:这是一个链接,无法翻译成中文) - Ciro Santilli OurBigBook.com
3个回答

78

以下内容引用自CREATE TABLE Syntax页面:

主键可以是多列索引。但是,您不能在列规范中使用PRIMARY KEY关键字属性创建多列索引。这样做只会将该单个列标记为主键。您需要使用单独的PRIMARY KEY(index_col_name,...)子句。

对于多列主键,可以使用类似以下的语法:

CREATE TABLE
    product (
        category INT NOT NULL,
        id INT NOT NULL,
        price DECIMAL,
        PRIMARY KEY(category, id)
    );

来自13.1.20.6 FOREIGN KEY Constraints


你的示例中,PK(类别、ID、价格)中不应该包括价格吗?他是在要求“任何列”和“跨所有列”吗?然后再加上一条严厉的评论,指出这种方法是次优的、缓慢的,并且在现实生活中从未需要过?(是的!我在挑剔:-) - lexu
我同意。所有列都应该在那里。 - fiacobelli
在我的情况下根本不起作用。例如,如果我使用不同的类别,但是相同的ID,仍然会显示重复的键。 - Bagusflyer
@bagusflyer 我遇到的一个问题是MySQL的类型转换导致两个原本不同的数据变成了相同的插入值,从而导致重复键,例如将字符串转换为数字或限制字符数。错误消息应该显示转换后的确切键值,这可以用来检查是否发生了转换。 - Sheepy

32

主键是一个领域概念,用于在类似实体之间唯一(必要且充分地)标识您的实体。仅当密钥的一部分引用另一个领域实体的特定实例时,复合(多列)主键才有意义。

假设您拥有个人图书收藏。只要您独自一人,就可以对其进行计数并为每一本书分配一个编号。该编号是您的图书馆领域的主键。

现在,您想将您的图书馆与邻居的图书馆合并,但仍希望能够区分每本书属于谁。领域现在更广泛,主键现在是(所有者,书籍编号)。

因此,将每个主键都组合起来不应该是您的策略,而是应在需要时使用它。

现在关于MySQL的一些事实。如果您定义了复合主键,并希望RDBSM自动为您增加ID,则应了解MyISAM和InnoDB行为之间的差异。

假设我们需要一个具有两个字段的表:parent_id,child_id。我们希望child_id自动递增。

MyISAM会在具有相同parent_id的记录中唯一自动递增,而InnoDB会在整个表中唯一自动递增。

在MyISAM中,应将主键定义为(parent_id,child_id),而在InnoDB中应定义为(child_id,parent_id),因为在InnoDB中,自动递增的字段应该是主键中最左边的组成部分。


3
这是一个杰出的答案。 - Dakatine

1
主键是行的唯一值。包括价格这样可能会改变的值是没有意义的。想象一下,如果您需要更改大量价格,那么所有这些主键值都将更改。那将是多么混乱!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接