【问题标题】:How to properly create composite primary keys - MYSQL如何正确创建复合主键 - MYSQL
【发布时间】:2011-08-15 17:04:56
【问题描述】:

这是我正在使用的密集设置的严重过度简化。 table_1table_2 都具有自动增量代理主键作为 ID。 info 是一个表,其中包含有关 table_1table_2 的信息。

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

我正在尝试决定是否应该将info 的主键组合成table_1table_2 的ID。如果我要这样做,其中哪一个最有意义?
(在此示例中,我将 ID 11209 与 ID 437 结合使用)

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

还是别的什么?

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

【问题讨论】:

标签: mysql primary-key myisam composite-key composite-primary-key


【解决方案1】:

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

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

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

【讨论】:

  • 哦,哇,这就是你制作复合键的方法!看起来我完全误解了这个概念。谢谢!!所以这样的事情完全是为了索引目的,那么正确吗?因为我无法通过使用此组合来引用记录,所以我仍然必须这样做 UPDATE info ... WHERE t1ID=11209 AND t2ID=437 ?
  • 正确。虽然由于两列都应该是唯一的,但 t1ID = 11209 可能就足够了。
  • @AlexCuse 两列的组合是唯一的,但是对于 t1ID = 11209,可以有任意数量的 t2ID。
【解决方案2】:

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

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

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

【讨论】:

  • 保持不同的列是绝对正确的。我不知道你可以有两列唯一索引,我认为这对我来说实际上可能是一个不错的选择。请问您为什么仍然希望将主键保持为自动增量?
  • 我没有真正令人信服的理由,我承认这是我和我的一些同事之间的争论点,因为更少的列更经济。我发现在单个外键上编写连接更容易。有时这些表的重要性“两个表之间的映射”变得与原始表一样重要,并且它的主键成为其他表中的外键列。
  • 谢谢。我觉得你说的很有道理,我会试试两列唯一索引+自增主键
  • 我想我的一个原因是你想创建一个关系表。您有三个表,例如市场、货币和提供商,提供商只能在市场中存在一次,因此您的关系表只能提供一种货币,因此您将复合 (id_market,id_provider) 意味着您只能制作该连接一次,尝试再次将相同的市场和提供商一起添加将失败,这意味着它们是唯一的,然后您将有第二列,例如 id_currency,这意味着货币在整个表中是单数的,这有意义吗?
  • 对于以后看到这个帖子的任何人,请注意这是不好的做法的原因是因为它违反了数据库设计的一个非常基本的原则。第一范式要求每条信息都有自己的列。几乎没有理由违反这一点以及规范化数据库结构的诸多好处。
【解决方案3】:

语法是 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)

【讨论】:

    【解决方案4】:

    假设您现在已经创建了一个表,您可以使用此查询来制作复合主键

    alter table employee add primary key(emp_id,emp_name);
    

    【讨论】:

      【解决方案5】:

      除了个人设计偏好之外,在某些情况下还想使用复合主键。表可能有两个或多个提供唯一组合的字段,不一定通过外键。

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

      如果数据库驱动一个动态网页,那么编写代码来查询两个字段的组合可能比提取/重新提交自动编号的键要简单得多。

      因此,虽然我没有回答最初的问题,但我当然很欣赏亚当的直接回答。

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:
          CREATE  TABLE `mom`.`sec_subsection` (
          
            `idsec_sub` INT(11) NOT NULL ,
          
            `idSubSections` INT(11) NOT NULL ,
          
            PRIMARY KEY (`idsec_sub`, `idSubSections`) 
          
          );
          

          【讨论】:

            【解决方案8】:

            @AlexCuse 我想将此作为评论添加到您的答案中,但在多次尝试在 cmets 中添加换行符失败后放弃了。

            也就是说,t1ID 在 table_1 中是唯一的,但这并不意味着它在 INFO 表中也是唯一的。

            例如:

            Table_1 有:
            标识字段
            1个
            2乙

            Table_2 有:
            标识字段
            1 X
            2年

            INFO 那么可以有:
            t1ID t2ID 字段
            1 1 一些
            1 2 数据
            每个 2 1 个
            2 2行

            所以在 INFO 表中唯一标识一行你需要 t1ID 和 t2ID

            【讨论】:

            • 它称为复合键
            • @PavelP 我的回复是 w.r.t Alex 的评论“虽然因为两列都应该是唯一的,但 t1ID = 11209 可能就足够了。” ...我同意使用复合键是正确的,但要确定完全匹配,您将需要 t1ID 和 t2ID ...我希望现在很清楚。
            猜你喜欢
            • 1970-01-01
            • 2014-06-13
            • 1970-01-01
            • 2017-07-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多