在MySQL中使用自动增量定义复合键

Nir*_*eri 22 mysql innodb composite-key auto-increment

场景:

我有一个引用两个外键的表,并且对于这些外键的每个唯一组合,都有自己的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)
);
Run Code Online (Sandbox Code Playgroud)

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

错误1075:表定义不正确; 只能有一个自动列,必须将其定义为键

我想要实现的目标:

我有一个Application Table(以app_id作为主键),每个Application都有一组要解决的问题,每个Application都有多个测试(所以test_id col)sr_no col应该为唯一的app_id和test_id递增.

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

在此输入图像描述

数据库引擎是InnoDB.我希望尽可能简单地实现这一点(即如果可能的话,避免使用触发器/程序 - 这是针对其他问题的类似情况而建议的).

noz*_*noz 29

您无法让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 ;
Run Code Online (Sandbox Code Playgroud)


Gor*_*ran 7

您可以使用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


Rol*_* NB 6

我不完全理解您对列的增量要求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 */
Run Code Online (Sandbox Code Playgroud)

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

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

  • 插入选择不一定是原子的。这取决于您的锁定设置/隔离级别。请参阅http://stackoverflow.com/questions/21438033/making-an-insert-select-statement-atomic,或http://dba.stackexchange.com/questions/73540/mysql-consist-nonlocking-reads-vs-插入-选择。 (2认同)