То есть я могу сначала попытаться обновить с помощью предложения where, если это не получится, затем вставить, а не наоборот?
Неясно, почему вы хотите это сделать.
Цель UPSERT - обеспечить, чтобы база данных содержала ровно одну строку с заданным ключом и заданным набором других значений столбца. Postgres сначала пытается выполнить INSERT, потому что INSERT потерпит неудачу, когда ключ конфликтует с дублирующейся строкой (так что он может вернуться к обновлению конфликтующей строки вместо того, чтобы вызвать исключение). ОБНОВЛЕНИЕ не завершится ошибкой, если предложение WHERE ничего не соответствует. успешно обновит ноль строк . ОБНОВЛЕНИЕ может завершиться ошибкой, если вы нарушите ограничение (например, ограничение CHECK или NOT NULL), но оно не завершится просто потому, что вы не сопоставили ни одной строки.
И, с другой стороны, если ваш UPDATE изменит существующую строку, то ваша INSERT обязательно потерпит неудачу с нарушением уникальности (поскольку строка существует). Таким образом, попытка INSERT сначала не меняет результат в этом случае.
Можно повесить условие на UPSERT в PostgreSQL с синтаксисом вида INSERT... ON CONFLICT DO UPDATE... WHERE...
. Это будет:
- Вставьте предоставленные вами строки.
- Для каждого конфликта с существующей строкой оцените условие WHERE для этой строки.
- Если условие WHERE удовлетворено, обновите существующую строку, в противном случае ничего не делайте с ней.
Я считаю, что это функционально эквивалентно тому, что вы просите, потому что:
- Если строка не существует, Postgres вставит ее. ОБНОВЛЕНИЕ не повлияло бы на это, таким образом, Ваш метод должен был бы все равно вернуться к ВСТАВКЕ.
- Если строка существует, но не соответствует предложению WHERE, Postgres ничего не сделает. Я думаю, что ваш метод либо ничего не сделает, либо потерпит неудачу с ограничением уникальности после попытки ВСТАВИТЬ его, но, возможно, у вас было другое соображение для этого случая.
- Если строка существует и соответствует предложению WHERE, Postgres и ваш метод выполнят ОБНОВЛЕНИЕ этой строки.