MySQL"好"的方法,如果找不到就插入一行,或者如果找到则更新它

Div*_*ero 16 mysql database-design upsert

通常,我想在我的一个用户上运行查询,我希望以1对1的关系存储与该用户相关联的行.所以,让我们说(这只是一个任意的例子),我有一个表跟踪用户的汽车,以及一些关于汽车的信息.每个用户可以拥有0或1辆汽车.如果用户没有汽车,则表中没有该用户的条目.

汽车表(再次,只是一个例子):id,user_id,car_make,car_model

所以,当我更新这个表时,我总是会做这样的事情(伪代码):

result = SELECT * FROM cars WHERE user_id=5
if (num_rows(result)>0){
    UPDATE cars SET car_make='toyota', car_model='prius' WHERE user_id=5
}else{
    INSERT INTO cars (user_id, car_make, car_model) VALUES (5, 'toyota', 'prius')
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能把它变成一个"原子地"起作用的优雅陈述?如果在另一个进程中SELECT和UPDATE语句之间的行被删除,会发生什么?我的UPDATE语句将失败INSERT语句应该运行的地方.我觉得我需要做两个相似(但不同)的陈述来完成同样的事情!我需要的是一些声明,它将向我保证我想要的数据存在于表中,特别是当我只想要一行满足我的要求时.例如,它可能是这样的(当然这是完全构成的):

MAKE SURE A ROW IN cars WHERE user_id=5 IS SET WITH car_make='toyota', car_model='prius'
Run Code Online (Sandbox Code Playgroud)

这样,如果user_id已经存在,那么它将被更新,否则将被插入.此外,如果我更改了要求,例如说每个用户可以拥有给定car_make的零个或一个汽车,那么我可以进一步指定:

MAKE SURE A ROW IN cars WHERE user_id=5 AND car_make='toyota' IS SET WITH car_model='prius'
Run Code Online (Sandbox Code Playgroud)

我希望我的问题有道理!如何改进这种经常出现的基本insert-if-not-found或update-if-found操作?谢谢你的帮助!

mis*_*hac 17

您可以使用" REPLACE INTO "或" INSERT ... ON DUPLICATE KEY UPDATE ".我相信第二个是你想要的,但有些情况下REPLACE INTO很方便.


def*_*nes 7

我的其他Stack Overflow回答:

如果你想在一个语句中这样做,我建议使用INSERT ... ON DUPLICATE KEY UPDATE语法,如下所示:

INSERT INTO table (id, someothervalue) VALUES (1, 'hi mom')
  ON DUPLICATE KEY UPDATE someothervalue = 'hi mom';
Run Code Online (Sandbox Code Playgroud)

INSERT如果没有具有指定键值(主键或唯一键)的现有记录,则将执行初始语句.如果记录已存在,则执行以下UPDATE语句(someothervalue = 3).

所有版本的MySQL都支持此功能.有关详细信息,请参阅MySQL参考手册页面INSERT ... ON DUPLICATE KEY UPDATE


jua*_*uan 0

在 Oracle 中你有Merge

对 MySql 不了解,但该术语可能会给您提供其他搜索内容。