2009-04-22 71 views
104

我有以下查询:MySQL ON DUPLICATE KEY - 最后一次插入ID?

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

我想无论是插入或更新的ID。通常我运行第二个查询来获得这个,因为我相信insert_id()只返回'已插入'的ID而不是已更新的ID。

有没有办法来插入/更新和检索行的ID而不运行两个查询?

+3

而不是假设,你为什么不自己测试它?上述编辑中的SQL确实有效,通过我的测试比捕获插入失败更快,使用INSERT IGNORE,或者选择先查看是否有重复。 – 2011-12-28 01:26:32

+1

警告:解决方案建议工作,但即使没有插入,auto_increment值也会继续增加。如果重复密钥经常发生,那么在上述查询之后,您可能想要运行`alter table tablename AUTO_INCREMENT = 0;`,以避免您的id值出现大的差距。 – 2016-04-22 06:00:54

回答

125

查看此网页纠正了:http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
在页面的底部,他们解释如何可以使LAST_INSERT_ID有意义的更新传递一个表达式TH在MySQL功能。

从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

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

+1

啊耶 - 我正在寻找的东西不会摆脱以前的ID – thekevinscott 2009-04-22 18:42:09

+0

这可能是危险的,因为这也可能会导致删除其他相关数据(通过约束)。 – Serge 2017-10-12 13:49:00

0

值得一提的,这可能是明显的(但无论如何,我会说这为清楚起见,在这里),即更换会吹走插入新数据之前的现有匹配行。 ON DUPLICATE KEY UPDATE只会更新您指定的列并保留该行。

manual

更换作品酷似INSERT, 不同之处在于,如果一个老行的表 具有相同的值作为新行的 主键或唯一索引,则在插入新行之前删除旧行 行。

25

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

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

和“身份证”比这个自动递增的主键将是工作的解决方案:

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 ...更新 插入一行,LAST_INSERT_ID()函数返回 AUTO_INCREMENT值。如果语句更新一行, LAST_INSERT_ID()没有意义。但是,您可以通过使用LAST_INSERT_ID(expr)解决此问题 。假设id是AUTO_INCREMENT 列。

0

如果您使用自动增量,现有的解决方案工作。我有一种情况,用户可以定义一个前缀,并且应该在3000处重新开始序列。由于前缀不同,我不能使用autoincrement,这使得insert_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。

相关问题