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

По какому принципу UNION исключает дубликаты при объединении SELECT-запросов

2.2 Middle🔥 211 комментариев
#Базы данных и SQL

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

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

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

Принцип удаления дубликатов в UNION

UNION — это оператор объединения результатов нескольких SELECT-запросов. Важное свойство UNION: он автоматически удаляет дубликаты при объединении результирующих наборов.

Основной механизм

UNION исключает дубликаты на основе полного совпадения строк. Две строки считаются дубликатом, если все значения во всех столбцах совпадают в точности.

-- Запрос 1: получает имена из таблицы employees
SELECT name FROM employees WHERE dept = 'IT'
RESULTAT:
name
-----------
Alice
Bob
Alice      -- дубликат

-- UNION: объединяет результаты и удаляет дубликаты
SELECT name FROM employees WHERE dept = 'IT'
UNION
SELECT name FROM contractors WHERE dept = 'IT'

РЕЗУЛЬТАТ (дубликаты удалены):
name
-----------
Alice
Bob
Charlie
David

Как UNION удаляет дубликаты

Внутренний алгоритм работает примерно так:

  1. Выполняет оба SELECT-запроса
  2. Объединяет результирующие наборы в один временный набор
  3. Сортирует строки (обычно по всем столбцам)
  4. Сканирует отсортированные данные
  5. Удаляет все последовательные дублирующиеся строки
  6. Возвращает результат
Набор 1:        Набор 2:        Объединено:     Отсортировано:  После удаления:
Alice           Charlie         Alice           Alice           Alice
Bob             David           Bob             Alice           Bob
Alice                           Charlie         Bob             Charlie
                                David           Charlie         David
                                                David

Полное совпадение всех столбцов

Дубликат определяется по совпадению ВСЕХ столбцов в результирующем наборе:

-- Пример 1: совпадают оба столбца = дубликат
SELECT id, name FROM table1
UNION
SELECT id, name FROM table2

Табло 1:  | Таблица 2:  | UNION результат:
id name  | id name     | id name
1  Alice | 1  Alice    | 1  Alice
2  Bob   | 3  Charlie  | 2  Bob
        |             | 3  Charlie

-- Пример 2: только имена совпадают, но id разные = НЕ дубликат
SELECT name FROM table1
UNION
SELECT name FROM table2

РЕЗУЛЬТАТ:
name
-----------
Alice
Bob
Charlie

UNION vs UNION ALL

-- UNION: удаляет дубликаты (медленнее)
SELECT email FROM users WHERE active = true
UNION
SELECT email FROM archived_users

Результат: каждый email встречается один раз

-- UNION ALL: сохраняет ВСЕ строки, включая дубликаты (быстрее)
SELECT email FROM users WHERE active = true
UNION ALL
SELECT email FROM archived_users

Результат: если email есть в обеих таблицах, он появится дважды

Стоимость операции удаления дубликатов

Удаление дубликатов требует дополнительные вычислительные ресурсы:

UNION:
1. Выполнение обоих запросов (T1)
2. Объединение результатов (T2)
3. Сортировка (O(n log n))
4. Удаление дубликатов - сканирование (O(n))
5. Возврат результата
Общая сложность: O(n log n)

UNION ALL:
1. Выполнение обоих запросов (T1)
2. Объединение результатов (T2)
Общая сложность: O(n)

Практический пример на Java + SQL

@Repository
public class UserRepository {
    @PersistenceContext
    private EntityManager em;
    
    // Используем нативный запрос с UNION
    @Query(value = """
        SELECT user_id, email FROM active_users
        WHERE created_at > ?1
        UNION
        SELECT user_id, email FROM vip_users
        WHERE status = 'GOLD'
    """, nativeQuery = true)
    List<Object[]> getUniqueUsers(LocalDateTime since);
    
    // UNION ALL если нужны все строки (без удаления дубликатов)
    @Query(value = """
        SELECT user_id, email FROM active_users
        WHERE created_at > ?1
        UNION ALL
        SELECT user_id, email FROM vip_users
        WHERE status = 'GOLD'
    """, nativeQuery = true)
    List<Object[]> getAllUsers(LocalDateTime since);
}

Важные моменты

  1. Тип данных: для UNION результаты должны иметь совместимые типы данных
  2. Порядок столбцов: совпадают по позиции, не по имени
  3. NULL значения: NULL = NULL при поиске дубликатов
  4. Производительность: UNION ALL значительно быстрее, если дубликаты не критичны
  5. Индексы: помогают ускорить выполнение исходных SELECT запросов, но не помогают в удалении дубликатов

Когда использовать UNION vs UNION ALL

  • UNION: когда логически должны быть уникальные строки (объединение двух списков)
  • UNION ALL: когда нужны все данные, или когда дубликатов быть не может
По какому принципу UNION исключает дубликаты при объединении SELECT-запросов | PrepBro