INSERT ... ON DUPLICATE KEY(不执行任何操作)
我有一个表,其中两列有一个唯一键:
CREATE TABLE `xpo`.`user_permanent_gift` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`fb_user_id` INT UNSIGNED NOT NULL ,
`gift_id` INT UNSIGNED NOT NULL ,
`purchase_timestamp` TIMESTAMP NULL DEFAULT now() ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `user_gift_UNIQUE` (`fb_user_id` ASC, `gift_id` ASC) );
我想在该表中插入一行,但如果该键存在,则不执行任何操作!我不希望因为密钥存在而生成错误。
我知道有以下语法:
INSERT ... ON DUPLICATE KEY UPDATE ...
但是有类似的东西吗
INSERT ... ON DUPLICATE KEY DO NOTHING
?
I have a table with a unique key for two columns:
CREATE TABLE `xpo`.`user_permanent_gift` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`fb_user_id` INT UNSIGNED NOT NULL ,
`gift_id` INT UNSIGNED NOT NULL ,
`purchase_timestamp` TIMESTAMP NULL DEFAULT now() ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `user_gift_UNIQUE` (`fb_user_id` ASC, `gift_id` ASC) );
I want to insert a row into that table, but if the key exists, to do nothing! I don't want an error to be generated because the keys exist.
I know that there is the following syntax:
INSERT ... ON DUPLICATE KEY UPDATE ...
but is there something like:
INSERT ... ON DUPLICATE KEY DO NOTHING
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
是的,使用 INSERT ... ON DUPLICATE KEY UPDATE id=id (即使将
id
分配给自身,它也不会触发行更新)。如果您不关心错误(转换错误、外键错误)和自动增量字段耗尽(即使由于重复键而未插入行,它也会递增),则可以像这样使用
INSERT IGNORE
:Yes, use
INSERT ... ON DUPLICATE KEY UPDATE id=id
(it won't trigger row update even thoughid
is assigned to itself).If you don't care about errors (conversion errors, foreign key errors) and autoincrement field exhaustion (it's incremented even if the row is not inserted due to duplicate key), then use
INSERT IGNORE
like this:如何实现“如果不存在则插入”?
1.
替换为
优点:
缺点:
太慢。 。
如果有条目匹配
唯一键
或主键
,则自动递增键将更改(增加1),因为它会删除旧条目然后插入新条目。2.
INSERT IGNORE
优点:
缺点:
如果有条目匹配
唯一键
或主键
,自动增量键不会改变,但自动增量索引会增加 1some其他错误/警告将被忽略,例如数据转换错误。
3.
INSERT ... ON DUPLICATE KEY UPDATE
优点:
缺点:
如果您只想插入而不更新,看起来相对复杂。
如果有条目匹配
唯一键
或主键
,自动增量键不会改变,但自动增量索引将增加14. 如果有任何方法可以阻止自动增量 key 增加条目是否匹配
唯一键
或主键
?正如 @toien 在下面的评论中提到的:如果您使用
innodb
作为引擎,“自动增量列将取决于 5.1 版本之后的innodb_autoinc_lock_mode
配置”,但是这也会影响并发性,所以使用前需要充分考虑。到目前为止我还没有看到更好的解决方案。HOW TO IMPLEMENT 'insert if not exist'?
1.
REPLACE INTO
pros:
cons:
too slow.
auto-increment key will CHANGE(increase by 1) if there is entry matches
unique key
orprimary key
, because it deletes the old entry then insert new one.2.
INSERT IGNORE
pros:
cons:
auto-increment key will not change if there is entry matches
unique key
orprimary key
but auto-increment index will increase by 1some other errors/warnings will be ignored such as data conversion error.
3.
INSERT ... ON DUPLICATE KEY UPDATE
pros:
cons:
looks relatively complex if you just want to insert not update.
auto-increment key will not change if there is entry matches
unique key
orprimary key
but auto-increment index will increase by 14. Any way to stop auto-increment key increasing if there is entry matches
unique key
orprimary key
?As mentioned in the comment below by @toien: "auto-increment column will be effected depends on
innodb_autoinc_lock_mode
config after version 5.1" if you are usinginnodb
as your engine, but this also effects concurrency, so it needs to be well considered before used. So far I'm not seeing any better solution.使用
ON DUPLICATE KEY UPDATE ...
,否定:因为
UPDATE
使用第二个操作的资源。使用
INSERT IGNORE ...
,负面:如果出现问题,MySQL 不会显示任何错误,因此您无法处理错误。仅当您不关心查询时才使用它。
Use
ON DUPLICATE KEY UPDATE ...
,Negative : because the
UPDATE
uses resources for the second action.Use
INSERT IGNORE ...
,Negative : MySQL will not show any errors if something goes wrong, so you cannot handle the errors. Use it only if you don’t care about the query.
您可以使用目标表的
左外连接
并在WHERE target.value is null
上进行过滤来实现此目的。如果没有选择插入匹配的行,您不必担心自动递增或更新。最近,我想将用户的所有用户 ID 和首选项中不存在行的所有首选项 ID 插入到我的
user_preferences
表中。在这里,我选择用户 ID 和首选项 ID 的列表(为了您的目的,忽略交叉连接,我只想为每个参考 ID 提供一个用户 ID 行),并在目标中尚不应该存在的两个值上进行左外连接表,
user_preferences
。使用
左外连接
,右侧表中的所有行都将返回与JOIN
条件中指定的左侧表匹配的值,否则将返回空。但这是完美的!由于
子句,意味着我们选择的内容将被插入。user_preferences
中没有与user_id
或preferences_id
匹配的值,因此它将匹配为空行,从而选择我们在user_preferences
中要求的值code>SELECT但是,如果您再次运行 select 子句(没有
INSERT
语句),则用户 ID 和首选项 ID 将匹配,因为它们现在位于表中,即它们不会为空,因此它们不会匹配target.id is null
条件,并且不会选择任何内容,因此不会插入任何内容。如果您想对单行尝试此操作,只需使用要在连接条件中显式插入的值,就像我可以说的那样
target.user_id = 9 和 target.preferences_id = 23
,因为它们不存在于右侧表中,我会返回一个空行,并且select 9, 23, 'enable_dark_scheme'
将被返回并因此被插入。非常方便的部分是您可以单独运行选择作为将插入的内容的预览。
You can do this with a
left outer join
of the target table and filter onWHERE target.value is null
. You don't have to worry about auto incrementing or updating if no matching rows are selected for insertion.Recently I wanted to insert into my
user_preferences
table all user IDs from users and all preference IDs from preferences where a row didn't already exist.Here I select a list of user IDs and preference IDs (ignore the cross join for your purposes, I just wanted a user ID row for every reference ID), and left outer joined on the two values that shouldn't yet exist in the target table,
user_preferences
.With the
left outer join
, all rows from the right hand table will be returned with values matching the left hand table as specified in theJOIN
condition, else it will returnnull
. But that's perfect! Since there's no value matchinguser_id
orpreferences_id
inuser_preferences
, it will match as an empty row and thus select the values we asked for in theSELECT
clause, meaning what we selected will be inserted.BUT if you run just the select clause again (without the
INSERT
statement), the user IDs and preference IDs WILL match since they're now in the table, i.e. they won't be null, so they won't match thetarget.id is null
condition and nothing will be selected, thus nothing inserted.If you want to try this for a single row, just use the values you want to insert explicitly in your join condition, like I could have said
target.user_id = 9 and target.preferences_id = 23
and since they don't exist in the right hand table, I'd get a null row back andselect 9, 23, 'enable_dark_scheme'
would be returned and therefore inserted.The very handy part of this is that you can run the select by itself as a preview of what will be inserted.