PostgreSQL INSERT ON CONFLICT UPDATE(upsert)使用所有排除的值

Seb*_*ian 108 postgresql upsert postgresql-9.5

当您要插入一行(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
Run Code Online (Sandbox Code Playgroud)

有更短的方式吗?只是说:使用所有EXCLUDE值.

在SQLite我以前做过:

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

Kri*_*ján 129

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;
Run Code Online (Sandbox Code Playgroud)

  • 需要注意的是,"on update"在语义上与SQL标准的"合并"不同,尽管它通常可以在相同的地方使用.我有一个案例,我期望"冲突更新"开始,但插入中的确切问题不会导致更新(这将修复损坏的记录)触发. (3认同)
  • 也许这不是冲突而是另一个错误,例如字段类型错误? (3认同)
  • 您可以扩展“但是插入中的确切问题没有导致更新”吗? (2认同)

小智 8

不幸的是,没有更短的方法来编写它。您必须在该部分中指定要更新的每一列do update

INSERT INTO tablename (id, username, password, level, email, update_count) 

-- if id doesn't exist, do insert
VALUES (1, 'John', 'qwerty', 5, 'john@mail.com', 0) 

-- how to check for duplicates (more versatile: could use any unique index here)
ON CONFLICT (id) 
DO UPDATE 
SET 
  -- update duplicate clause
  username=EXCLUDED.username, -- references proposed insertion row
  password=EXCLUDED.password,
  level=EXCLUDED.level,
  email=EXCLUDED.email,
  update_count=tablename.update_count+1 -- reference existing row
Run Code Online (Sandbox Code Playgroud)

on conflict将为您提供类似于insert or replacesqlite 的功能,但它是一个更通用的功能,更专注于update而不是仅仅进行整行替换。