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

Какие знаешь ограничения UNION?

2.0 Middle🔥 141 комментариев
#Базы данных (SQL)

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

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

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

Ограничения UNION в SQL

UNION — это операция для объединения результатов двух или более SELECT запросов. Несмотря на кажущуюся простоту, у него есть важные ограничения и подводные камни.

Основное определение

UNION объединяет результаты с удалением дубликатов:

SELECT name FROM users
UNION
SELECT name FROM customers;

UNION ALL объединяет со всеми дубликатами:

SELECT name FROM users
UNION ALL
SELECT name FROM customers;  -- Быстрее, т.к. без дедубликации

1. Количество и тип колонок должны совпадать

ПЛОХО:

SELECT id, name FROM users           -- 2 колонки
UNION
SELECT email FROM customers;  -- 1 колонка — ОШИБКА!

ХОРОШО:

SELECT id, name FROM users
UNION
SELECT id, email FROM customers;  -- Одинаковое количество

2. Типы данных колонок должны быть совместимы

ПЛОХО:

SELECT id::INTEGER, name FROM users     -- int, varchar
UNION
SELECT email::VARCHAR, created_at::TIMESTAMP FROM customers;
-- Типы не совпадают!

ХОРОШО:

SELECT CAST(id AS VARCHAR) AS identifier, name FROM users
UNION
SELECT email AS identifier, created_at::VARCHAR FROM customers;

3. Имена колонок берутся из первого запроса

Результат:

SELECT id, name FROM users      -- Имена: id, name
UNION
SELECT user_id, email FROM customers;
-- Результат имеет колонки: id, name (из первого запроса)

4. UNION автоматически сортирует результаты

Проблема: UNION (без ALL) медленнее из-за сортировки для удаления дубликатов:

-- МЕДЛЕННО: требует сортировки O(n log n)
SELECT name FROM users
UNION
SELECT name FROM customers;

-- БЫСТРО: нет сортировки
SELECT name FROM users
UNION ALL
SELECT name FROM customers;

5. Нельзя использовать ORDER BY в подзапросах

ПЛОХО:

SELECT name FROM users
ORDER BY name  -- ОК
UNION
SELECT name FROM customers
ORDER BY name;  -- ОШИБКА

ХОРОШО:

(SELECT name FROM users)
UNION
(SELECT name FROM customers)
ORDER BY name;  -- ORDER BY только в конце

6. Нельзя использовать LIMIT в подзапросах (в некоторых БД)

PostgreSQL позволяет:

SELECT name FROM users LIMIT 5
UNION
SELECT name FROM customers LIMIT 3;

MySQL строгий:

(SELECT name FROM users LIMIT 5)
UNION
(SELECT name FROM customers LIMIT 3);  -- Требуются скобки

7. Производительность падает с количеством объединений

-- 10 UNION — может быть медленно
SELECT name FROM users
UNION
SELECT name FROM customers
UNION
SELECT name FROM partners
UNION
SELECT name FROM contractors
-- ... ещё 6 раз

Решение: Использовать UNION ALL если дубликаты не критичны.

8. UNION не сохраняет порядок отдельных наборов

-- Порядок users не сохранится
SELECT name, 1 as source FROM users ORDER BY name
UNION
SELECT name, 2 as source FROM customers;
-- ORDER BY применяется ПОСЛЕ UNION

Решение: Использовать source колонку для сортировки:

SELECT name, 1 as source FROM users
UNION
SELECT name, 2 as source FROM customers
ORDER BY source, name;  -- Сортируем по источнику

9. NULL обрабатывается как значение

SELECT NULL as value
UNION
SELECT NULL as value;
-- Результат: одна строка с NULL (UNION удалил дубликат)

SELECT NULL as value
UNION ALL
SELECT NULL as value;
-- Результат: две строки с NULL

10. Нельзя использовать JOIN с UNION напрямую

ПЛОХО:

SELECT u.id, u.name FROM users u
UNION
SELECT c.id, c.name FROM customers c
JOIN orders o ON c.id = o.customer_id;
-- ОШИБКА: неправильный синтаксис

ХОРОШО:

SELECT u.id, u.name FROM users u
UNION
SELECT c.id, c.name 
FROM customers c
JOIN orders o ON c.id = o.customer_id;  -- JOIN внутри подзапроса

Практические примеры

Поиск по нескольким таблицам

from sqlalchemy import union_all

# Найти "John" в users и customers
users_query = session.query(User.id, User.name, literal('user').label('type')).filter(User.name.like('%John%'))
customers_query = session.query(Customer.id, Customer.name, literal('customer').label('type')).filter(Customer.name.like('%John%'))

result = session.query(union_all(users_query, customers_query)).all()
for id, name, type in result:
    print(f"{name} ({type})")

Комбинирование разных таблиц (версионирование)

-- Получить текущие и архивные записи
SELECT id, name, created_at FROM users
WHERE is_active = true
UNION ALL
SELECT id, name, created_at FROM users_archive
ORDER BY created_at DESC;

Выбор лучшего варианта между UNION и JOIN

-- С JOIN (обычно быстрее)
SELECT u.id, u.name, c.country
FROM users u
LEFT JOIN customers c ON u.id = c.user_id;

-- С UNION (медленнее, но нужен при разных структурах)
SELECT u.id, u.name, NULL as country FROM users u
WHERE u.id NOT IN (SELECT user_id FROM customers)
UNION
SELECT c.user_id, u.name, c.country
FROM customers c
JOIN users u ON c.user_id = u.id;

Таблица: Различия

ХарактеристикаUNIONUNION ALL
ДубликатыУдаляетОставляет
СкоростьМедленнее (сортировка)Быстрее
ПамятьБольшеМеньше
Когда использоватьНужны уникальные значенияНужны все значения

Практические рекомендации

  • Используйте UNION ALL если дубликаты допустимы (быстрее)
  • Проверяйте типы и количество колонок перед UNION
  • Используйте алиасы для ясности (SELECT 1 as source)
  • Помещайте ORDER BY в конце, а не в подзапросы
  • Рассмотрите альтернативы: CASE, JOIN, временные таблицы
  • Профилируйте UNION запросы — они могут быть медленными

Вывод: UNION — мощный инструмент, но требует понимания его ограничений и побочных эффектов. Часто JOIN или временные таблицы работают быстрее.

Какие знаешь ограничения UNION? | PrepBro