← Назад к вопросам
По какому принципу 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 удаляет дубликаты
Внутренний алгоритм работает примерно так:
- Выполняет оба SELECT-запроса
- Объединяет результирующие наборы в один временный набор
- Сортирует строки (обычно по всем столбцам)
- Сканирует отсортированные данные
- Удаляет все последовательные дублирующиеся строки
- Возвращает результат
Набор 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);
}
Важные моменты
- Тип данных: для UNION результаты должны иметь совместимые типы данных
- Порядок столбцов: совпадают по позиции, не по имени
- NULL значения: NULL = NULL при поиске дубликатов
- Производительность: UNION ALL значительно быстрее, если дубликаты не критичны
- Индексы: помогают ускорить выполнение исходных SELECT запросов, но не помогают в удалении дубликатов
Когда использовать UNION vs UNION ALL
- UNION: когда логически должны быть уникальные строки (объединение двух списков)
- UNION ALL: когда нужны все данные, или когда дубликатов быть не может