PostgreSQL INSERT ON CONFLICT UPDATE (upsert) использовать все исключенные значения

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

Есть более короткий путь? Просто сказать: используйте все значения ИСКЛЮЧЕНИЯ.

В 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, и вам не нужно беспокоиться о столбцах
j будет

Ответы:

163

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-парень
2
Можете ли вы расширить "но точная проблема во вставке не вызвала обновление"?
MrR
@ pojo-guy - я не думаю, что вы видели вопрос от MrR - Можете ли вы остановиться на «но точная проблема во вставке не вызвала обновление»?
Рэндалл
Когда вы пытаетесь использовать insert ... при обновлении в postgresql, результаты в некоторых конкретных случаях отличаются от результатов слияния. Случай, с которым я столкнулся, был довольно неясным и конкретным, но его можно было повторить. Прошло несколько месяцев, поэтому я не могу дать больше прав.
pojo-guy
Возможно, это был не конфликт, а другая ошибка, например ошибка типа поля?
МРР