UNION или UNION ALL: почему изменилось число строк

Два списка клиентов содержат одного человека дважды. UNION убирает совпадение, а UNION ALL оставляет его. Что выбрать — зависит от того, считаете вы людей или события.

SQL Studio / Разборы SQL / UNION или UNION ALL: почему изменилось число строк

Разница: UNION соединяет результаты запросов и убирает полностью одинаковые строки. UNION ALL сохраняет все строки, включая повторы. Ни один вариант не «правильнее» без понимания, что означает строка.

1. UNION: три уникальных клиента вместо четырёх записей

В первом списке клиенты 1 и 2, во втором — 2 и 3. Эти данные создаются через VALUES, таблицы заранее не нужны.

WITH a(customer_id) AS (VALUES (1), (2)),
     b(customer_id) AS (VALUES (2), (3))
SELECT customer_id FROM a
UNION
SELECT customer_id FROM b
ORDER BY customer_id;

Результат — 1, 2, 3. Клиент 2 встретился дважды, но в итоговом списке остался один раз. Это подходит, если требуется множество уникальных идентификаторов.

2. UNION ALL: сохраняем оба появления клиента

WITH a(customer_id) AS (VALUES (1), (2)),
     b(customer_id) AS (VALUES (2), (3))
SELECT customer_id FROM a
UNION ALL
SELECT customer_id FROM b
ORDER BY customer_id;

Результат — 1, 2, 2, 3. Если строки отражают события, второй клиент мог совершить два действия. Убирать одну запись только из-за одинакового customer_id было бы ошибкой.

3. Повторный платёж — не дубликат строки

В учебной базе payments заказ может иметь неудачную и успешную попытки. Объединим номера заказов из обеих групп и проверим, какие встретились дважды.

SELECT order_id, COUNT(*) AS attempts_n
FROM (
  SELECT order_id FROM payments WHERE status = 'failed'
  UNION ALL
  SELECT order_id FROM payments WHERE status = 'captured'
)
GROUP BY order_id
HAVING COUNT(*) > 1
ORDER BY order_id;
Заказы с неудачной и успешной попытками
order_idattempts_n
2012
2062

Если заменить UNION ALL на UNION, повтор номера заказа исчезнет, и запрос ошибочно покажет, что таких заказов нет. При этом сами попытки оплаты никуда из базы не пропали — потеря произошла только в результате SQL.

4. UNION ALL для денежных движений

Поступления и возвраты имеют разные знаки. Их удобно объединить в поток движений, затем посчитать итог. Берём только подтверждённые платежи и все возвраты из учебной таблицы.

WITH movements AS (
  SELECT amount_kopecks AS delta
  FROM payments WHERE status = 'captured'
  UNION ALL
  SELECT -amount_kopecks AS delta
  FROM refunds
)
SELECT SUM(delta) / 100.0 AS net_rub
FROM movements;

Получится 1 160 ₽: поступления 1 250 ₽ минус возвраты 90 ₽. Здесь UNION опасен: если два движения имеют одинаковые суммы, он может удалить одно из них. В финансовых данных у каждого события должен сохраняться собственный идентификатор.

Проверить самостоятельно

Сначала посмотрите на попытки оплат, затем проверьте денежный итог без соединения нескольких таблиц «один ко многим».

Рядом по смыслу: почему одинаковые ключи не всегда дубликаты · оплаты и возвраты без размножения строк.

Синтаксис объединения результатов: официальная документация SQLite.


Для последовательной практики на MySQL 8 — курс «SQL для аналитика» на Stepik с итоговой работой и возможностью получить сертификат.