148

我有以下查询:

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

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

有没有办法在不运行两个查询的情况下插入/更新并检索行的 ID?

4

7 回答 7

197

查看此页面: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;
于 2009-04-22T21:13:10.593 回答
39

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

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 列。

于 2012-08-10T19:11:54.170 回答
2

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

于 2009-04-22T18:40:41.957 回答
2

我不知道你的 MySQL 版本是什么,但是使用 InnoDB,autoinc 存在错误

5.1.20 中的错误并在 5.1.23 中更正 http://bugs.mysql.com/bug.php?id=27405

5.1.31 中的错误并在 5.1.33 中更正 http://bugs.mysql.com/bug.php?id=42714

于 2009-04-22T21:02:49.540 回答
1

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

于 2019-11-26T12:50:49.733 回答
0

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

手册

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

于 2009-11-05T15:03:58.383 回答
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。

于 2015-06-02T00:24:02.797 回答