sql - 使用 postgres 进行幂等插入

标签 sql postgresql

我想要这样的东西

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/

相关文章:

php - MYSQL IF 语句到不同的 WHERE 子句

sql - 从两个表中选择所有列 postgresql 函数

postgresql - 如何从 Postgres docker 镜像更改 postgresql.conf

c# - SQLite 数据库 (.db) 的性能问题

mysql - 是否可以一次插入相同的值(Mysql)?

mysql - 在 INSERT 语句中执行 SELECT 语句的 SQL 是什么?

mysql - 如何通过多个关系过滤 SQL 查询?

node.js - Nodejs 整数错误输入语法无效

ruby-on-rails - 如何重置我的 heroku 数据库?

sql - 什么是表示数据库中两个不同用户输入的数据的有效方法