【问题标题】:Defining Composite Key with Auto Increment in MySQL在 MySQL 中使用自动增量定义复合键
【发布时间】:2013-08-09 19:34:17
【问题描述】:

场景:

我有一个引用两个外键的表,对于这些外键的每个唯一组合,都有自己的 auto_increment 列。我需要实现一个复合键,这将有助于使用这三个(一个外键和一个 auto_increment 列,以及另一个具有非唯一值的列)的组合来识别行是唯一的

表格:

CREATE  TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
  `app_id` INT NOT NULL ,
  `test_id` INT NOT NULL ,
  `issue_name` VARCHAR(255) NOT NULL ,
primary key (app_id, test_id,sr_no)
);

当然,我的查询肯定有问题,因此抛出的错误是:

ERROR 1075:表定义不正确;只能有一辆汽车 列,它必须被定义为一个键

我想要达到的目标:

我有一个应用程序表(以 app_id 作为其主键),每个应用程序都有一组要解决的问题,每个应用程序都有多个测试(所以 test_id col) sr_no col 应该为唯一的 app_id 和 test_id 递增。

即表中的数据应如下所示:

数据库引擎是 InnoDB。 我想以尽可能简单的方式实现这一点(即尽可能避免触发器/程序 - 这是针对其他问题的类似情况建议的)。

【问题讨论】:

    标签: mysql innodb auto-increment composite-key


    【解决方案1】:

    为什么不尝试将声明字段的位置更改为主键,因为当您使用“auto_increment”时,它必须作为第一个引用。比如下面的例子

    CREATE  TABLE `issue_log` (
    `sr_no` INT NOT NULL AUTO_INCREMENT ,
      `app_id` INT NOT NULL ,
      `test_id` INT NOT NULL ,
      `issue_name` VARCHAR(255) NOT NULL ,
    primary key (sr_no,app_id, test_id)
    );
    

    【讨论】:

      【解决方案2】:

      只需在自动增量列上添加键(sr_no):

      CREATE  TABLE `issue_log` (
       `sr_no` INT NOT NULL AUTO_INCREMENT ,
       `app_id` INT NOT NULL ,
       `test_id` INT NOT NULL ,
       `issue_name` VARCHAR(255) NOT NULL ,
        primary key (app_id, test_id,sr_no),
        key (`sr_no`)
      );
      

      【讨论】:

        【解决方案3】:

        我不完全理解您对 test_id 列的增量要求,但如果您想要一个在 (app_id, test_id) 的每个唯一组合上重新启动的 ~autoincrement 序列,您可以执行 INSERT 。 .. SELECT FROM 同一张表,像这样:

        mysql> INSERT INTO `issue_log` (`sr_no`, `app_id`, `test_id`, `issue_name`) SELECT
                   IFNULL(MAX(`sr_no`), 0) + 1 /* next sequence number */,
                   3 /* desired app_id */,
                   1 /* desired test_id */,
                   'Name of new row'
                   FROM `issue_log` /* specify the table name as well */
               WHERE `app_id` = 3 AND `test_id` = 1 /* same values as in inserted columns */
        

        这假定一个表定义没有声明 AUTO_INCREMENT 列。您实际上是在使用 IFNULL(MAX()) + 1 子句模拟自动增量行为,但手动模拟适用于任意列,这与内置自动增量不同。

        请注意,INSERT ... SELECT 作为单个查询可确保操作的原子性。 InnoDB 将间隙锁定适当的索引,许多并发进程可以执行这种查询,同时仍然产生不冲突的序列。

        【讨论】:

        【解决方案4】:

        您不能让 MySQL 为您自动为 InnoDB 表执行此操作 - 您需要使用触发器或过程,或使用其他数据库引擎,例如 MyISAM。自动递增只能对单个主键进行。

        类似下面的东西应该可以工作

        DELIMITER $$
        
        CREATE TRIGGER xxx BEFORE INSERT ON issue_log
        FOR EACH ROW BEGIN
            SET NEW.sr_no = (
               SELECT IFNULL(MAX(sr_no), 0) + 1
               FROM issue_log
               WHERE app_id  = NEW.app_id
                 AND test_id = NEW.test_id
            );
        END $$
        
        DELIMITER ;
        

        【讨论】:

        • 好的,我应该在 Create Table 查询中做哪些更改?我不能让 sr_no 成为主键,因为它不会是唯一的。如果不将其设为主键,我将无法使其成为自动增量......
        • 只需关闭自动增量 - 它无法满足您的需求。主键保持不变。
        • 很抱歉我没有使用触发器,并且此触发器代码抛出“语法错误” - 没有定义其他任何内容。你能清理一下代码,一旦完成,在这里发表评论吗?错误是: ERROR 1064: You have an error in your SQL syntax;检查与您的 MySQL 服务器版本相对应的手册,以在第 3 行的 '.sr_no=(select ifnull(select max(sr_no)+1 from issue_log where app_id=new.app_id' 附近使用正确的语法
        • 抱歉,缺少 SET - 我已将其添加到文本中。
        • 静止和错误;错误在以“set...”开头的行上,在第二次选择时,它显示“unexpected SELECT_SYM”语法错误。
        【解决方案5】:

        您可以使用 myISAM 和 BDB 引擎执行此操作。 InnoDB 不支持这个。引用自 MySQL 5.0 参考手册。

        对于 MyISAM 和 BDB 表,您可以在多列索引的辅助列上指定 AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT 列的生成值计算为 MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。

        http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

        【讨论】:

        • 仅供参考,在 Stack Overflow 上始终首选引用相关信息和链接,仅将提问者引至链接即可删除答案。
        【解决方案6】:

        您可以为sr_noapp_idtest_id 使用unique 复合键。您不能在 sr_no 中使用增量,因为这不是唯一的。

        CREATE TABLE IF NOT EXISTS `issue_log` (
          `sr_no` int(11) NOT NULL,
          `app_id` int(11) NOT NULL,
          `test_id` int(11) NOT NULL,
          `issue_name` varchar(255) NOT NULL,
          UNIQUE KEY `app_id` (`app_id`,`test_id`,`sr_no`)
        ) ENGINE=InnoDB ;
        

        我已经在sql fiddle 中注释掉了唯一约束违规以进行演示(删除模式第 22 行中的 # 并重建模式)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-16
          • 1970-01-01
          • 2012-08-11
          • 2014-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-01
          相关资源
          最近更新 更多