当前位置:  开发笔记 > 后端 > 正文

如何更新表中的行或如果它不存在则插入它?

如何解决《如何更新表中的行或如果它不存在则插入它?》经验,为你挑选了6个好方法。

我有下表的柜台:

CREATE TABLE cache (
    key text PRIMARY KEY,
    generation int
);

我想增加其中一个计数器,或者如果相应的行还不存在则将其设置为零.有没有办法在标准SQL中没有并发问题的情况下执行此操作?该操作有时是交易的一部分,有时是分开的.

如果可能的话,SQL必须在SQLite,PostgreSQL和MySQL上不加修改地运行.

搜索产生了一些想法,这些想法要么遇到并发问题,要么特定于数据库:

尝试换INSERT行,UPDATE如果出现错误.不幸的是,INSERT中止当前事务的错误.

UPDATE行,如果没有修改行,则为INSERT新行.

MySQL有一个ON DUPLICATE KEY UPDATE条款.

编辑:感谢所有的好评.看起来保罗是对的,并没有单一,便携的方式来做到这一点.这对我来说非常令人惊讶,因为它听起来像是一个非常基本的操作.



1> andygeers..:

MySQL(以及随后的SQLite)也支持REPLACE INTO语法:

REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');

这会自动识别主键并找到要更新的匹配行,如果没有找到则插入新行.


重要的是要理解它是插入+删除而永远不会更新.这样做的结果是,您总是希望确保在进行替换时,应始终包含所有字段的数据.
实际上,具体来说,MySQL的REPLACE总是进行插入,但是如果它已经存在,它将首先删除该行.http://dev.mysql.com/doc/refman/4.1/en/replace.html
>(以及后来的SQLite)......你完全从我的回答中偷走了:-)
对不起 - 希望不被认为粗鲁?
@Zoredache从技术上讲,它是一个'删除,然后插入',因为(n)'insert + delete'实际上与删除相同但是分裂头发.
@Agihammerthief有一个非常实际的区别,即新插入的行与已删除的行将不具有相同的主键。使用ON DUPLICATE,它将是相同的主键(除非您专门对其进行更改)。

2> Kyle Cronin..:

SQLite支持替换已存在的行:

INSERT OR REPLACE INTO [...blah...]

你可以缩短这个

REPLACE INTO [...blah...]

添加此快捷方式以与MySQL REPLACE INTO表达式兼容.



3> jmoz..:

我会做类似以下的事情:

INSERT INTO cache VALUES (key, generation)
ON DUPLICATE KEY UPDATE (key = key, generation = generation + 1);

在代码或sql中将生成值设置为0,但使用ON DUP ...来增加值.无论如何,我认为这就是语法.



4> Fire Crow..:

ON DUPLICATE KEY UPDATE子句是最好的解决方案,因为:REPLACE执行一个DELETE后跟一个INSERT,所以在一个非常小的时间段内删除记录会产生一个很小的可能性,如果页面是,那么查询可以返回跳过在REPLACE查询期间查看.

我更喜欢INSERT ...在DUPLICATE UPDATE ...出于这个原因.

jmoz的解决方案是最好的:虽然我更喜欢SET语法到括号

INSERT INTO cache 
SET key = 'key', generation = 'generation'
ON DUPLICATE KEY 
UPDATE key = 'key', generation = (generation + 1)
;


REPLACE是原子的,因此没有行不存在的时间段.

5> BradC..:

我不知道你会找到一个平台中立的解决方案.

这通常称为"UPSERT".

看一些相关的讨论:

SQL Server上INSERT或UPDATE的解决方案

SQL REP 2005实现MySQL REPLACE INTO?



6> 小智..:

在PostgreSQL中没有合并命令,实际上编写它并不是一件容易的事 - 实际上有一些奇怪的边缘情况使得任务"有趣".

最好的(如:在最可能的条件下工作)方法是使用函数 - 例如手动(merge_db)中显示的函数.

如果您不想使用功能,通常可以逃脱:

updated = db.execute(UPDATE ... RETURNING 1)
if (!updated)
  db.execute(INSERT...)

请记住,它不是故障证明,最终失败.

推荐阅读
N个小灰流_701
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有