防止MySQL重复插入时自动增加

rob*_*ert 37 mysql innodb insert duplicates auto-increment

使用MySQL 5.1.49,我正在尝试实现一个标记系统我遇到的问题是带有两列的表:id(autoincrement),tag(unique varchar) (InnoDB)

使用查询时,即使忽略插入INSERT IGNORE INTO tablename SET tag="whatever",自动增量id值也会增加.

通常这不会是一个问题,但我希望很多可能的尝试为这个特定的表插入重复项,这意味着我id的新行的字段的下一个值将跳得太多.

例如,我最终会得到一张表3行但不好id的表

1   | test
8   | testtext
678 | testtextt
Run Code Online (Sandbox Code Playgroud)

此外,如果我不这样做INSERT IGNORE并且只是定期INSERT INTO处理错误,则自动增量字段仍会增加,因此下一个真正的插入仍然是错误的自动增量.

如果有INSERT重复的行尝试,有没有办法停止自动增量?

正如我对MySQL 4.1的理解,这个值不会增加,但我想做的最后一件事是要么SELECT提前做很多语句来检查标签是否存在,或者更糟糕的是,降级我的MySQL版本.

mu *_*ort 22

你可以修改你的INSERT是这样的:

INSERT INTO tablename (tag)
SELECT $tag
FROM tablename
WHERE NOT EXISTS(
    SELECT tag
    FROM tablename
    WHERE tag = $tag
)
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

如果$tag尚未添加标记(正确引用或当然占位符),则添加到哪里.如果标签已经存在,这种方法甚至不会触发INSERT(以及随后的自动增量浪费).你可能会提出比这更好的SQL,但上面应该可以解决问题.

如果您的表被正确编入索引,则存在检查的额外SELECT将很快,并且数据库无论如何都必须执行该检查.

但是,这种方法不适用于第一个标签.您可以使用您认为最终将被使用的标记为您的标记表设定种子,或者您可以对空表进行单独检查.

  • 很好的解决方案,在最初插入行时遇到一些麻烦.我发现如果您选择的表是空的,则不会发生插入. (3认同)

Per*_*son 14

v 5.5的MySQL文档说:

"If you use INSERT IGNORE and the row is ignored, the AUTO_INCREMENT counter 
is **not** incremented and LAST_INSERT_ID() returns 0, 
which reflects that no row was inserted."
Run Code Online (Sandbox Code Playgroud)

参考:http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id

从版本5.1开始,InnoDB具有可配置的自动增量锁定功能.另见http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html#innodb-auto-inc ...

解决方法:使用选项innodb_autoinc_lock_mode = 0(传统).


Jam*_*mie 13

我刚发现这个宝石......

http://www.timrosenblatt.com/blog/2008/03/21/insert-where-not-exists/

INSERT INTO [table name] SELECT '[value1]', '[value2]' FROM DUAL
WHERE NOT EXISTS(
    SELECT [column1] FROM [same table name]
    WHERE [column1]='[value1]'
    AND [column2]='[value2]' LIMIT 1
)
Run Code Online (Sandbox Code Playgroud)

如果affectedRows = 1则插入; 否则如果affectedRows = 0则有重复.


Lan*_*don 12

我发现mu太短的答案很有帮助,但限制因为它不会在空表上插入.我找到了一个简单的修改方法:

INSERT INTO tablename (tag)
SELECT $tag
FROM (select 1) as a     #this line is different from the other answer
WHERE NOT EXISTS(
    SELECT tag
    FROM tablename
    WHERE tag = $tag
)
LIMIT 1
Run Code Online (Sandbox Code Playgroud)

用"伪"表替换from子句中的表(select 1) as a允许该部分返回允许插入发生的记录.我正在运行mysql 5.5.37.感谢mu让我大部分时间到那里....