Можно ли выполнить upsert, который требует фильтрации в Postgres? - PullRequest
0 голосов
/ 07 ноября 2018

Мне интересно, возможно ли использовать следующий оператор для выполнения upsert w / filtering. То есть я могу сначала попытаться обновить с предложением where, если это не удается, а затем вставить, а не наоборот? Я хотел бы сделать это в Postgres.

ВСТАВИТЬ ... В КОНФЛИКТ НИЧЕГО НЕ ДЕЛАТЬ / ОБНОВИТЬ

Я видел это, но это определенно немного сложнее https://dba.stackexchange.com/questions/13468/idiomatic-way-to-implement-upsert-in-postgresql

1 Ответ

0 голосов
/ 08 ноября 2018

То есть я могу сначала попытаться обновить с помощью предложения where, если это не получится, затем вставить, а не наоборот?

Неясно, почему вы хотите это сделать.

Цель UPSERT - обеспечить, чтобы база данных содержала ровно одну строку с заданным ключом и заданным набором других значений столбца. Postgres сначала пытается выполнить INSERT, потому что INSERT потерпит неудачу, когда ключ конфликтует с дублирующейся строкой (так что он может вернуться к обновлению конфликтующей строки вместо того, чтобы вызвать исключение). ОБНОВЛЕНИЕ не завершится ошибкой, если предложение WHERE ничего не соответствует. успешно обновит ноль строк . ОБНОВЛЕНИЕ может завершиться ошибкой, если вы нарушите ограничение (например, ограничение CHECK или NOT NULL), но оно не завершится просто потому, что вы не сопоставили ни одной строки.

И, с другой стороны, если ваш UPDATE изменит существующую строку, то ваша INSERT обязательно потерпит неудачу с нарушением уникальности (поскольку строка существует). Таким образом, попытка INSERT сначала не меняет результат в этом случае.

Можно повесить условие на UPSERT в PostgreSQL с синтаксисом вида INSERT... ON CONFLICT DO UPDATE... WHERE.... Это будет:

  1. Вставьте предоставленные вами строки.
  2. Для каждого конфликта с существующей строкой оцените условие WHERE для этой строки.
  3. Если условие WHERE удовлетворено, обновите существующую строку, в противном случае ничего не делайте с ней.

Я считаю, что это функционально эквивалентно тому, что вы просите, потому что:

  1. Если строка не существует, Postgres вставит ее. ОБНОВЛЕНИЕ не повлияло бы на это, таким образом, Ваш метод должен был бы все равно вернуться к ВСТАВКЕ.
  2. Если строка существует, но не соответствует предложению WHERE, Postgres ничего не сделает. Я думаю, что ваш метод либо ничего не сделает, либо потерпит неудачу с ограничением уникальности после попытки ВСТАВИТЬ его, но, возможно, у вас было другое соображение для этого случая.
  3. Если строка существует и соответствует предложению WHERE, Postgres и ваш метод выполнят ОБНОВЛЕНИЕ этой строки.
...