Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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
- Производительность — один запрос вместо нескольких
- Атомарность — либо все операции выполнены, либо ни одна
- Читаемость — вся логика в одном месте
- Меньше блокировок — таблица заблокирована один раз
- Проще отладка — одна операция, один результат
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 — это мощный инструмент для работы с данными, который значительно упрощает код и повышает производительность.