我想要这样的东西
INSERT VALUES(1,2,3) INTO sometable ON CONFLICT DO NOTHING IF EXACTLY SAME ROW
所以我想要以下行为:
#CREATE TABLE sometable (a int primary key, b int, c int);
CREATE TABLE
#INSERT INTO sometable (1,2,3) ON CONFLICT DO NOTHING IF EXACTLY SAME ROW
INSERT 0 1
#INSERT INTO sometable (1,2,3) ON CONFLICT DO NOTHING IF EXACTLY SAME ROW
INSERT 0 0
#INSERT INTO sometable (1,3,2) ON CONFLICT DO NOTHING IF EXACTLY SAME ROW
ERROR: duplicate key value violates unique constraint "sometable_pkey"
DETAIL: Key (a)=(1) already exists.
希望这似乎是一件很自然的事情,因为客户端应用程序不能假设它会知道插入是否成功(如果 postgres 或客户端崩溃或网络出现故障,请求可能已被处理但客户端永远不会收到确认).因此,任何编写良好的应用程序都需要以某种方式处理这种情况。
但是,我发现实现这一点的最不坏的方法仍然很烦人:
INSERT INTO sometable (a,b,c) VALUES(1,2,3) ON CONFLICT(a) UPDATE set sometable.b=2 WHERE sometable.b=2 AND sometable.c=3;
换句话说,执行无操作更新,但前提是值是您要插入的值,然后如果触摸到 0 行(而不是 1 行)则抛出错误。
有没有更好的办法?
最佳答案
您可以使用基于选择的 INSERT:
insert into sometable
select *
from ( values (1,2,3) ) as data(a,b,c)
where not exists (select *
from sometable
where data = sometable);
是的,条件 where data = sometable
在 Postgres 中是有效的,它只是比较所有列。
这也可以扩展到多行:
insert into sometable
select *
from (
values
(1,2,3),
(4,5,6),
(7,8,9)
) as data(a,b,c)
where not exists (select *
from sometable
where data = sometable);
如果从多个事务中完成,这不会防止 PK 违规错误(如 on conflict
所做的那样)。您仍然需要处理这些错误。
关于sql - 使用 postgres 进行幂等插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47452603/