使用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
另外,如果我不执行INSERT IGNORE
并且只执行常规INSERT INTO
并处理错误,则自动增量字段仍会增加,因此下一个真正的插入仍然是错误的自动增量。
如果有INSERT
重复的行尝试,有没有办法停止自动增量?
正如我对MySQL 4.1所理解的那样,这个值不会增加,但我要做的最后一件事是要么提前做很多SELECT
语句来检查标签是否存在,或者更糟糕的是,降级我的MySQL版本。
答案 0 :(得分:22)
您可以将INSERT修改为:
INSERT INTO tablename (tag)
SELECT $tag
FROM tablename
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)
LIMIT 1
其中$tag
是您要添加的标记(正确引用或作为占位符)(如果尚未添加)。如果标签已经存在,这种方法甚至不会触发INSERT(以及随后的自动增量浪费)。你可能会提出比这更好的SQL,但上面应该可以解决这个问题。
如果你的表被正确编入索引,那么存在检查的额外SELECT将很快,数据库将不得不执行该检查。
但这种方法不适用于第一个标签。您可以使用您认为最终将被使用的标记为您的标记表设定种子,或者您可以对空表进行单独检查。
答案 1 :(得分: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."
参考: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(传统)。
答案 2 :(得分:11)
我刚发现这个宝石......
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
)
如果affectedRows = 1则插入;否则,如果affectedRows = 0则有重复。
答案 3 :(得分:10)
我发现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
使用“伪”表(select 1) as a
替换from子句中的表允许该部分返回允许插入发生的记录。我正在运行mysql 5.5.37。非常感谢mu让我在那里大部分时间......
答案 4 :(得分:3)
您可以随时添加ON DUPLICATE KEY UPDATE
Read here(不完全相同,但似乎可以解决您的问题)。
来自@ravi的评论
增量是否发生取决于 innodb_autoinc_lock_mode设置。如果设置为非零值,则 即使ON DUPLICATE KEY触发
,auto-inc计数器也会递增
答案 5 :(得分:1)
我有同样的问题,但不想使用innodb_autoinc_lock_mode = 0,因为我觉得我用榴弹炮杀死了一只苍蝇。
要解决此问题,我最终使用临时表。
create temporary table mytable_temp like mytable;
然后我插入了值:
insert into mytable_temp values (null,'valA'),(null,'valB'),(null,'valC');
之后,您只需执行另一次插入,但使用“not in”忽略重复项。
insert into mytable (myRow) select mytable_temp.myRow from mytable_temp
where mytable_temp.myRow not in (select myRow from mytable);
我没有对性能进行测试,但是它完成了工作,并且易于阅读。虽然这很重要,因为我正在处理不断更新的数据,所以我不能忽视这些差距。
答案 6 :(得分:1)
接受的答案很有用,但是我在使用它时遇到了问题,基本上如果你的表没有条目,它就不会工作,因为选择使用了给定的表,所以相反我想出了以下内容,即使表是空白也插入,它也只需要你将表插入2个位置并将插入变量放在1个地方,少发生错误。
INSERT INTO database_name.table_name (a,b,c,d)
SELECT
i.*
FROM
(SELECT
$a AS a,
$b AS b,
$c AS c,
$d AS d
/*variables (properly escaped) to insert*/
) i
LEFT JOIN
database_name.table_name o ON i.a = o.a AND i.b = o.b /*condition to not insert for*/
WHERE
o.a IS NULL
LIMIT 1 /*Not needed as can only ever be one, just being sure*/
希望你觉得它很有用
答案 7 :(得分:0)
我在插入/更新查询后添加了一条额外的语句:
ALTER TABLE table_name
AUTO_INCREMENT = 1
然后他会自动获取最高的原始密钥ID加1。
答案 8 :(得分:0)
修改了 mu 的答案太短,(只需删除一行) 因为我是新手,我无法在他的回答下方发表评论。直接发到这里
下面的查询适用于第一个标签
INSERT INTO tablename (tag)
SELECT $tag
WHERE NOT EXISTS(
SELECT tag
FROM tablename
WHERE tag = $tag
)