PostgreSQL在冲突更新中插入(向上更新)使用所有排除的值


142

当您升级一行(PostgreSQL> = 9.5),并且希望可能的INSERT与可能的UPDATE完全相同时,可以这样编写:

INSERT INTO tablename (id, username, password, level, email) 
                VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') 
ON CONFLICT (id) DO UPDATE SET 
  id=EXCLUDED.id, username=EXCLUDED.username,
  password=EXCLUDED.password, level=EXCLUDED.level,email=EXCLUDED.email

有没有更短的方法?只能说:使用所有EXCLUDE值。

在SQLite中,我曾经做过:

INSERT OR REPLACE INTO tablename (id, user, password, level, email) 
                        VALUES (1, 'John', 'qwerty', 5, 'john@mail.com')

43
这不是一个真正的答案,但是您可以使用简短的表示法: INSERT INTO tablename (id, username, password, level, email) VALUES (1, 'John', 'qwerty', 5, 'john@mail.com') ON CONFLICT (id) DO UPDATE SET (username, password, level, email) = (EXCLUDED.username, EXCLUDED.password, EXCLUDED.level, EXCLUDED.email).几乎相同,但易于复制/粘贴/管理列列表

另一种选择是使用jsonb列,这样你就不必对列的担心
Ĵ将

Answers:


162

Postgres尚未实现与的等效项INSERT OR REPLACE。从ON CONFLICT文档(重点是我的):

它可以是DO NOTHING,也可以是DO UPDATE子句,指定发生冲突时要执行的UPDATE操作的确切详细信息

尽管它不能为您提供替换的捷径ON CONFLICT DO UPDATE,但由于它使您可以基于现有数据设置新值,因此更适用。例如:

INSERT INTO users (id, level)
VALUES (1, 0)
ON CONFLICT (id) DO UPDATE
SET level = users.level + 1;

3
请注意,“更新时”在语义上与SQL标准的“合并”并不相同,尽管通常可以在相同的地方使用它。我有一个案例,我希望“冲突更新”会启动,但是插入中的确切问题并未引起更新(该更新会修复损坏的记录)。
pojo-guy

2
您可以扩展“但是插入中的确切问题没有导致更新”吗?
MrR

@ pojo-guy-我认为您没有看到MrR提出的问题-您可以扩展“但插入内容中的确切问题没有引起更新”吗?
Randall

当您尝试在postgresql的更新中使用insert ...时,在某些特定情况下,结果与合并不同。我遇到的这个案例比较晦涩和具体,但是可以重复。已经几个月了,所以我不能再给任何权利了。
pojo-guy

也许这不是冲突,而是另一个错误,例如字段类型错误?
MrR
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.