我有以下查询:
INSERT INTO table (a) VALUES (0)
ON DUPLICATE KEY UPDATE a=1
我想要插入或更新的 ID。通常我会运行第二个查询以获得此信息,因为我相信 insert_id() 仅返回“插入”ID 而不是更新后的 ID。
有没有办法在不运行两个查询的情况下插入/更新并检索行的 ID?
查看此页面: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;
确切地说,如果这是原始查询:
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 列。
您可能会查看 REPLACE,如果记录存在,它本质上是一个删除/插入。但这会改变自动增量字段(如果存在),这可能会破坏与其他数据的关系。
我不知道你的 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
我遇到了一个问题,当 ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id) 将主键增加 1。所以会话中下一个输入的 id 将增加 2
值得注意的是,这可能很明显(但为了清楚起见,我还是会这么说),REPLACE 会在插入新数据之前清除现有的匹配行。ON DUPLICATE KEY UPDATE 只会更新您指定的列并保留该行。
从手册:
REPLACE 的工作方式与 INSERT 完全相同,只是如果表中的旧行与 PRIMARY KEY 或 UNIQUE 索引的新行具有相同的值,则在插入新行之前删除旧行。
如果您使用自动增量,现有的解决方案就可以工作。我有一种情况,用户可以定义一个前缀,它应该在 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。