MERGE

MERGE сопоставляет источник с целевой таблицей и выполняет разные действия для совпавших и несовпавших строк. Точный синтаксис и конкурентные гарантии заметно различаются между СУБД.

MERGE INTO user_totals AS target
USING daily_totals AS source
   ON target.user_id = source.user_id
WHEN MATCHED THEN
    UPDATE SET total = source.total
WHEN NOT MATCHED THEN
    INSERT (user_id, total)
    VALUES (source.user_id, source.total);

Для чего подходит

  • синхронизация staging-таблицы с основной;
  • пакетное обновление и вставка;
  • загрузка подготовленной проекции;
  • описание нескольких ветвей обработки одним оператором.

Это не универсальная идемпотентность

Повтор операции безопасен только если бизнес-ключ, исходные данные и действия спроектированы для повтора. MERGE сам по себе не защищает от двойного внешнего эффекта.

Конкуренция

Две сессии могут одновременно решить, что строки нет, и попытаться вставить ее. Нужны:

  • UNIQUE на ключе сопоставления;
  • понимание блокировок конкретной СУБД;
  • обработка конфликта/retry;
  • иногда специальный UPSERT (INSERT ... ON CONFLICT, ON DUPLICATE KEY) вместо MERGE.

Ловушки

  • Несколько строк источника, совпавших с одной строкой цели, могут вызвать ошибку или неоднозначное поведение.
  • Условие ON должно совпадать с реальным ключом, иначе обновится не та гранулярность.
  • Триггеры и порядок ветвей зависят от реализации.
  • Нельзя переносить пример между диалектами без проверки.

Связано: Ограничения, constraints, Ключи БД, Транзакции принцип ACID.

Вопросы

Чем MERGE отличается от UPDATE? Он умеет выбирать действие в зависимости от наличия сопоставленной строки.

Нужен ли UNIQUE при upsert? Да, именно ограничение является последней защитой уникальности при конкуренции.

Гарантирует ли MERGE отсутствие гонок? Не автоматически; гарантии зависят от СУБД, индексов и уровня изоляции.