MySQL - 如何在不使用AUTO_INCREMENT的情况下添加唯一的INT值?

时间:2017-08-07 21:41:37

标签: mysql sql database innodb

我有一个MySQL表。我必须能够为速度添加唯一的INT值,而不是AUTO_INCREMENT列。

CREATE TABLE ki
(
  id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT
  , comp_id INT(10) UNSIGNED NOT NULL
  , speed INT(4) UNSIGNED NOT NULL DEFAULT 0
  , position INT(4) UNSIGNED NOT NULL DEFAULT 0

  , PRIMARY KEY (id)

  , UNIQUE INDEX (comp_id, speed, position)
  , INDEX (comp_id)

  , FOREIGN KEY (comp_id)
      REFERENCES competitions (id)
        ON DELETE NO ACTION
        ON UPDATE CASCADE
) ENGINE=InnoDB CHARACTER SET latin1 COLLATE latin1_swedish_ci;

我想插入新行。

INSERT INTO ki (comp_id, speed, position) VALUES (1, 1, 0)
INSERT INTO ki (comp_id, speed, position) VALUES (1, 2, 0)
INSERT INTO ki (comp_id, speed, position) VALUES (1, 3, 0)
INSERT INTO ki (comp_id, speed, position) VALUES (1, 3, 0) -- error
INSERT INTO ki (comp_id, speed, position) VALUES (2, 1, 0)
INSERT INTO ki (comp_id, speed, position) VALUES (2, 3, 0)
INSERT INTO ki (comp_id, speed, position) VALUES (2, 2, 0)

对于每个comp_id,速度值从1开始。速度值应始终为comp_id的最大速度值+ 1。

如果(1, 3, 0)已存在,则插入内容应为(1, max(speed) where comp_id = 1, 0)。换句话说,(1, 4, 0)

我不想修改现有的行。

我怎样才能在SQL查询中执行此操作?据说,速度必须是唯一的,如果同时有几个插入,这必须有效。

如果同时有多个插入,以下方式是否可以起作用并保证一个独特的速度值(从1开始的值)?

INSERT INTO ki (comp_id, speed, position) 
VALUES (
   1, 
   COALESCE((SELECT MAX(ki2.speed)  
     FROM ki AS ki2 
     WHERE ki2.comp_id = 1 
   ), 1) + 1,
   0
)

2 个答案:

答案 0 :(得分:1)

使用INSERT INTO ... SELECT声明:

INSERT INTO ki(comp_id, position, speed)
  SELECT 1, 0, max(speed)+1
  FROM ki

小心!这至少有两个陷阱:

  1. 插入第一行需要特殊处理空值
  2. 更重要的是,这可能会导致竞争条件,因此您最好使用AUTO_INCREMENT来解决导致插入失败时出现间隙的问题
  3. 虽然通过coalesce(max(speed),0)+1包装陷阱很容易处理,但第二个陷阱是一个真正的危险,通常你需要考虑到这一点,或者只是创建UNIQUE INDEXspeed列上,并且赛车查询在任何尝试失败,但首先使用相同的值。

答案 1 :(得分:0)

我假设你不能使用自动增量,因为你已经有了其中之一?如果速度必须是唯一的,那么为什么它不是表上的PK并且摆脱自动增量列和自动增量速度反而?

但是,如果Speed应具有意义并在插入时定义,那么您有一个不同的问题。在这种情况下,您可以定义速度的唯一索引,如果值已经存在,则在插入时失败。或者,如果速度不存在,则编写存储过程以插入,如果存在,则更新记录。您选择的是数据含义和业务规则的函数。