MySQL ON DUPLICATE KEY-最后插入ID?


132

我有以下查询:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE a=1

我想要插入或更新的ID。通常我会运行第二个查询来获取此信息,因为我相信insert_id()仅返回“插入的” ID,而不返回更新的ID。

有没有一种方法可以在不运行两个查询的情况下进行INSERT / UPDATE和检索行ID?


3
而不是假设,您为什么不自己进行测试?上面的编辑中的SQL确实有效,通过我的测试,使用插入INSERT IGNORE或选择先查找是否有重复项比捕获插入失败的速度更快。
Michael Fenwick

4
警告:建议的解决方案有效,但是即使没有插入,auto_increment值也会继续增加。如果重复键经常发生,则可能要alter table tablename AUTO_INCREMENT = 0;在上述查询之后运行,以避免id值出现较大差距。
Frank Forte

Answers:


174

检出此页面:https : //web.archive.org/web/20150329004325/https : //dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
在页面底部他们解释了如何通过将表达式传递给该MySQL函数来使LAST_INSERT_ID对更新有意义。

从MySQL文档示例中:

如果表包含AUTO_INCREMENT列,并且INSERT ... UPDATE插入一行,则LAST_INSERT_ID()函数将返回AUTO_INCREMENT值。如果该语句改为更新一行,则LAST_INSERT_ID()没有意义。但是,您可以通过使用LAST_INSERT_ID(expr)解决此问题。假设id是AUTO_INCREMENT列。为了使LAST_INSERT_ID()对于更新有意义,请按如下所示插入行:

INSERT INTO table (a,b,c) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;

2
在浏览该页面时,我以某种方式错过了它。因此,更新部分显示为:UPDATE id = LAST_INSERT_ID(id),而且效果很好。谢谢!
thekevinscott

7
据说在两种情况下php函数mysql_insert_id()返回正确的值:php.net/manual/en/function.mysql-insert-id.php#59718
jayarjo 2010年

2
@PetrPeller-好吧,如果不查看MySQL内部信息,它可能意味着它将产生一个值,但是该值与您刚运行的查询无关。换句话说,这是一个很难调试的问题。
杰森

13
在5.1.12之后,不再需要这样做,但是今天我发现了一个例外。如果您具有自动增量pk,并且在电子邮件地址上具有唯一键,并且基于该电子邮件地址触发“重复更新”,则请注意last_insert_id不会是已更新行的自动增量值。它似乎是最近插入的自动增量值。这有很大的不同。解决方法与此处显示的相同,即在更新查询中使用id = LAST_INSERT_ID(id)。
sckd 2014年

1
在5.5上@sckd的评论仍然成立。
e18r

37

确切地说,如果这是原始查询:

INSERT INTO table (a) VALUES (0)
 ON DUPLICATE KEY UPDATE a=1

和'id'是自动递增的主键,比这是可行的解决方案:

INSERT INTO table (a) VALUES (0)
  ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1

全部在这里:http : //dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

如果表包含AUTO_INCREMENT列,并且INSERT ... UPDATE插入一行,则LAST_INSERT_ID()函数将返回AUTO_INCREMENT值。如果该语句改为更新一行,则LAST_INSERT_ID()没有意义。但是,您可以通过使用LAST_INSERT_ID(expr)解决此问题。假设id是AUTO_INCREMENT列。


7
是的,与您所说的相同,请参见接受的答案。无需恢复3岁的帖子。无论如何,谢谢您的努力。
fancyPants 2012年

1
@tombom我发布此答案的唯一原因是因为接受的答案不正确-如果没有任何更新,它将无法正常工作。
Aleksandar Popovic '11年

2

您可能会看到REPLACE,如果记录存在,它实际上是一个删除/插入。但这将更改自动增量字段(如果存在),这可能会破坏与其他数据的关系。


1
是的-我正在寻找一种不会
遗漏

这也可能很危险,因为这也可能导致其他相关数据的删除(受约束)。
Serge


1

我遇到一个问题,当ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id)将主键增加1时,会话中下一个输入的id将增加2。


0

值得注意的是,这可能很明显(但是我还是会为了清楚起见在这里说),REPLACE会在插入新数据之前吹走现有的匹配行。ON DUPLICATE KEY UPDATE将仅更新您指定的列并保留该行。

手册

REPLACE的工作方式与INSERT完全相同,不同之处在于,如果表中的旧行与PRIMARY KEY或UNIQUE索引的新行具有相同的值,则在插入新行之前会删除该旧行。


0

如果使用自动增量,则现有的解决方案将起作用。我遇到一种情况,用户可以定义前缀,并且应该在3000处重新启动序列。由于前缀的变化,我无法使用自动增量,这会使last_insert_id为插入内容为空。我用以下方法解决了它:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1);
SELECT LAST_INSERT_ID();

如果前缀存在,它将增加它并填充last_insert_id。如果前缀不存在,它将插入前缀值3000,并用3000填充last_insert_id。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.