← Назад к вопросам

Что такое MERGE в SQL?

2.0 Middle🔥 131 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

MERGE в SQL — слияние данных

MERGE — это SQL оператор, который комбинирует операции INSERT, UPDATE и DELETE в одно выражение. Он используется для синхронизации данных между источником и целевой таблицей на основе условия сопоставления.

Назначение MERGE

MERGE решает проблему, когда нужно:

  • Обновить существующие записи
  • Вставить новые записи
  • Удалить некоторые записи
  • Всё это за один запрос

Это намного эффективнее, чем выполнять несколько отдельных операций.

Синтаксис MERGE

MERGE INTO target_table AS t
USING source_table AS s
ON t.id = s.id
WHEN MATCHED AND condition THEN
    UPDATE SET t.column1 = s.column1
WHEN MATCHED AND NOT condition THEN
    DELETE
WHEN NOT MATCHED THEN
    INSERT (id, column1, column2) 
    VALUES (s.id, s.column1, s.column2)

Пример: синхронизация прайса товаров

Таблица исходных данных:

-- products_source — новые данные с поставщика
CREATE TABLE products_source (
    id INT,
    name VARCHAR(100),
    price DECIMAL(10, 2),
    stock INT
);

INSERT INTO products_source VALUES
(1, 'Laptop', 999.99, 5),
(2, 'Mouse', 29.99, 100),
(3, 'Monitor', 299.99, 20);

Целевая таблица:

CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    price DECIMAL(10, 2),
    stock INT,
    updated_at TIMESTAMP
);

INSERT INTO products VALUES
(1, 'Laptop', 899.99, 3, NOW()),
(2, 'Mouse', 29.99, 50, NOW());

MERGE оператор:

MERGE INTO products AS p
USING products_source AS ps
ON p.id = ps.id
WHEN MATCHED THEN
    UPDATE SET 
        p.name = ps.name,
        p.price = ps.price,
        p.stock = ps.stock,
        p.updated_at = NOW()
WHEN NOT MATCHED THEN
    INSERT (id, name, price, stock, updated_at)
    VALUES (ps.id, ps.name, ps.price, ps.stock, NOW());

Результат:

  • Товар 1: обновлён (цена 999.99, stock 5)
  • Товар 2: обновлён (всё совпадает, но дата обновления)
  • Товар 3: вставлен новый

Условные действия (WHEN clause)

Вы можете добавить дополнительные условия:

MERGE INTO products AS p
USING products_source AS ps
ON p.id = ps.id
WHEN MATCHED AND ps.stock > 0 THEN
    UPDATE SET 
        p.price = ps.price,
        p.stock = ps.stock
WHEN MATCHED AND ps.stock = 0 THEN
    DELETE
WHEN NOT MATCHED AND ps.stock > 0 THEN
    INSERT (id, name, price, stock)
    VALUES (ps.id, ps.name, ps.price, ps.stock);

Тут:

  • Если товар совпадает И есть в наличии → обновляем
  • Если товар совпадает И нет в наличии → удаляем
  • Если товар новый И есть в наличии → вставляем

MERGE в разных базах данных

PostgreSQL (9.5+) — похож на стандарт:

MERGE INTO employees e
USING new_employees ne ON e.id = ne.id
WHEN MATCHED THEN UPDATE SET name = ne.name
WHEN NOT MATCHED THEN INSERT (id, name) VALUES (ne.id, ne.name);

SQL Server — использует ON DUPLICATE KEY UPDATE:

MERGE INTO dbo.employees AS target
USING (SELECT * FROM new_employees) AS source
ON target.employee_id = source.employee_id
WHEN MATCHED THEN
    UPDATE SET target.salary = source.salary
WHEN NOT MATCHED THEN
    INSERT (employee_id, name, salary)
    VALUES (source.employee_id, source.name, source.salary);

MySQL — использует INSERT ... ON DUPLICATE KEY UPDATE:

INSERT INTO products (id, name, price, stock)
VALUES (3, 'Monitor', 299.99, 20)
ON DUPLICATE KEY UPDATE
    price = VALUES(price),
    stock = VALUES(stock);

Преимущества MERGE

  1. Производительность — один запрос вместо нескольких
  2. Атомарность — либо все операции выполнены, либо ни одна
  3. Читаемость — вся логика в одном месте
  4. Меньше блокировок — таблица заблокирована один раз
  5. Проще отладка — одна операция, один результат

MERGE vs отдельные запросы

Без MERGE (медленнее, опасно):

# Три отдельных запроса — могут быть проблемы
for item in new_data:
    if exists(item.id):
        UPDATE ...
    else:
        INSERT ...

С MERGE (быстрее, безопаснее):

-- Один атомарный запрос
MERGE INTO products ...

Практический пример на Python с SQLAlchemy

from sqlalchemy import text
from sqlalchemy.orm import Session

def sync_products(session: Session, new_products):
    merge_sql = text("""
        MERGE INTO products AS p
        USING (SELECT :id as id, :name as name, :price as price) AS ps
        ON p.id = ps.id
        WHEN MATCHED THEN
            UPDATE SET p.name = ps.name, p.price = ps.price
        WHEN NOT MATCHED THEN
            INSERT (id, name, price) VALUES (ps.id, ps.name, ps.price)
    """)
    
    for product in new_products:
        session.execute(merge_sql, {
            'id': product.id,
            'name': product.name,
            'price': product.price
        })
    session.commit()

Когда использовать MERGE

  • Синхронизация таблиц между системами
  • Обновление данных с импорта
  • Уникальные ключи конфликты
  • Пакетная обработка больших объёмов
  • ETL процессы

MERGE — это мощный инструмент для работы с данными, который значительно упрощает код и повышает производительность.