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

Возможно, это был не конфликт, а другая ошибка, например ошибка типа поля?
МРР
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.