Операции над наборами строк

Реляционная модель опирается на множества, но SQL по умолчанию использует bag semantics: результат может содержать дубликаты.

UNION

Объединяет строки двух результатов:

SELECT user_id FROM orders WHERE state = 'NEW'
UNION
SELECT user_id FROM orders WHERE state = 'PAID';

UNION удаляет дубликаты, UNION ALL сохраняет.

INTERSECT

Оставляет строки, присутствующие в обоих результатах:

SELECT user_id FROM orders WHERE state = 'NEW'
INTERSECT
SELECT user_id FROM orders WHERE state = 'PAID';

Так находятся пользователи, у которых есть и новые, и оплаченные заказы. Поддержка INTERSECT ALL зависит от СУБД.

EXCEPT

Оставляет строки первого результата, отсутствующие во втором:

SELECT id FROM users
EXCEPT
SELECT user_id FROM orders;

Это пользователи без заказов. В некоторых диалектах аналог называется MINUS.

Требования

  • одинаковое число столбцов;
  • совместимые типы в соответствующих позициях;
  • общий ORDER BY после всей операции;
  • имена результата обычно задает первая ветвь.

NULL и дубликаты

Для set operations строки с NULL могут считаться дубликатами/совпадающими по правилам операции, хотя обычное сравнение NULL = NULL дает UNKNOWN.

Альтернативные формы

Пересечение можно выразить EXISTS, разность — NOT EXISTS. Выбор делают по читаемости, требуемой семантике дубликатов и плану.

Связано: Объединение запросов, оператор UNION, Оператор EXISTS, Исключение дубликатов, DISTINCT.

Вопросы

Почему SQL-результат не всегда множество? По умолчанию дубликаты сохраняются.

Чем UNION отличается от UNION ALL? Первый удаляет дубликаты, второй нет.

Что делает INTERSECT? Возвращает общие строки.

Как найти строки A без соответствия в B? EXCEPT или корректный NOT EXISTS.