在MySQL中使用Auto_increment定义复合键

时间:2013-08-08 07:17:11

标签: mysql innodb auto-increment composite-key

情境:

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

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

  

错误1075:表定义不正确;只有一个汽车   列,它必须定义为键

我想要实现的目标:

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

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

enter image description here

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

6 个答案:

答案 0 :(得分:27)

您不能让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 ;

答案 1 :(得分: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

答案 2 :(得分:3)

您可以使用sr_no复合键app_idtest_id& 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 ; 中使用增量,因为这不是唯一的。

{{1}}

我在unique中注释了唯一约束违规,以演示(删除架构第22行中的#并重建架构)

答案 3 :(得分:3)

我不完全理解test_id列上的增量要求,但是如果你想要一个〜自动增量序列重新启动(app_idtest_id)的每个唯一组合,你可以在同一个表中执行INSERT ... SELECT,如下所示:

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 :(得分:0)

只需在自动增量列上添加密钥(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`)
);

答案 5 :(得分:0)

为什么不尝试将声明字段的位置更改为主键,因为当您使用“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)
);