Rem*_*ank 80 mysql sql sqlite postgresql upsert
我有下表的柜台:
CREATE TABLE cache (
key text PRIMARY KEY,
generation int
);
Run Code Online (Sandbox Code Playgroud)
我想增加其中一个计数器,或者如果相应的行还不存在则将其设置为零.有没有办法在标准SQL中没有并发问题的情况下执行此操作?该操作有时是交易的一部分,有时是分开的.
如果可能的话,SQL必须在SQLite,PostgreSQL和MySQL上不加修改地运行.
搜索产生了一些想法,这些想法要么遇到并发问题,要么特定于数据库:
尝试换INSERT行,UPDATE如果出现错误.不幸的是,INSERT中止当前事务的错误.
UPDATE行,如果没有修改行,则为INSERT新行.
MySQL有一个ON DUPLICATE KEY UPDATE条款.
编辑:感谢所有的好评.看起来保罗是对的,并没有单一,便携的方式来做到这一点.这对我来说非常令人惊讶,因为它听起来像是一个非常基本的操作.
and*_*ers 133
MySQL(以及随后的SQLite)也支持REPLACE INTO语法:
REPLACE INTO my_table (pk_id, col1) VALUES (5, '123');
Run Code Online (Sandbox Code Playgroud)
这会自动识别主键并找到要更新的匹配行,如果没有找到则插入新行.
Kyl*_*nin 31
INSERT OR REPLACE INTO [...blah...]
Run Code Online (Sandbox Code Playgroud)
你可以缩短这个
REPLACE INTO [...blah...]
Run Code Online (Sandbox Code Playgroud)
添加此快捷方式以与MySQL REPLACE INTO表达式兼容.
jmo*_*moz 21
我会做类似以下的事情:
INSERT INTO cache VALUES (key, generation)
ON DUPLICATE KEY UPDATE (key = key, generation = generation + 1);
Run Code Online (Sandbox Code Playgroud)
在代码或sql中将生成值设置为0,但使用ON DUP ...来增加值.无论如何,我认为这就是语法.
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)
;
Run Code Online (Sandbox Code Playgroud)
我不知道你会找到一个平台中立的解决方案.
这通常称为"UPSERT".
看一些相关的讨论:
小智 5
在PostgreSQL中没有合并命令,实际上编写它并不是一件容易的事 - 实际上有一些奇怪的边缘情况使得任务"有趣".
最好的(如:在最可能的条件下工作)方法是使用函数 - 例如手动(merge_db)中显示的函数.
如果您不想使用功能,通常可以逃脱:
updated = db.execute(UPDATE ... RETURNING 1)
if (!updated)
db.execute(INSERT...)
Run Code Online (Sandbox Code Playgroud)
请记住,它不是故障证明,最终会失败.
| 归档时间: |
|
| 查看次数: |
126368 次 |
| 最近记录: |