При объединении двух выборок через UNION откуда берутся имена столбцов результирующего набора?
Имена столбцов результата UNION или UNION ALL берутся из первой выборки, то есть из первого оператора SELECT. Имена и псевдонимы столбцов последующих выборок на названия результата не влияют.
Столбцы сопоставляются по позиции, а не по именам. Поэтому первый столбец первой выборки определяет имя первого столбца всего объединения, второй — имя второго и так далее.
Операции над множествами позволяют объединять результаты независимых запросов без ручного соединения их через JOIN. Для такой модели нужно было определить не только правила объединения строк, но и структуру единого результирующего отношения.
Поэтому SQL использует позиционное соответствие столбцов, а имена результата берет из первой ветви. Это делает структуру результата предсказуемой независимо от того, как названы поля в остальных ветвях.
Представим, что одна ветвь называет значение client_id, а другая — account_id. Если ожидать, что оба имени сохранятся, можно неправильно настроить внешний запрос, ORM-маппинг или экспорт отчёта.
При этом изменение порядка ветвей может изменить имена столбцов результата, хотя сами строки останутся теми же. Кроме того, для каждой позиции должны быть совместимы типы значений из всех ветвей.
В результате объединения имя каждой колонки определяется соответствующей колонкой первого SELECT. Псевдонимы последующих SELECT используются только внутри их собственного запроса и не переименовывают общий результат.
У combined будет один столбец с именем client_id, хотя во второй ветви он назван account_id. Внешний запрос обращается именно к имени, полученному от первой ветви.
Количество столбцов во всех ветвях должно совпадать. Значения сопоставляются по порядку: первый столбец одной ветви объединяется с первым столбцом другой, даже если их имена различаются.
UNION дополнительно удаляет дубликаты, а UNION ALL сохраняет их, но правило выбора имён у них одинаковое. Если объединение заключено в CTE с явным списком имён столбцов, внешний запрос увидит имена из этого списка; это отдельный уровень переименования.
Чтобы контракт результата не зависел от случайного порядка ветвей, обычно задают согласованные выражения и явно переименовывают столбцы в первой ветви. При необходимости внешний SELECT может дополнительно задать окончательные имена.
В отчёте объединили активных и архивных клиентов. В активной таблице идентификатор назывался client_id, а в архивной — legacy_id. Разработчик ориентировался на имя второй ветви и получил ошибку при обращении к legacy_id во внешнем запросе.
Можно было поменять порядок ветвей, но это лишь сделало бы контракт зависимым от структуры запроса и могло изменить типы, выбираемые для соответствующих позиций. Надёжнее оставить первой ветвь с каноническими именами и привести вторую ветвь к той же логической структуре.
В результате внешний отчёт всегда использовал client_id, а изменения внутренних названий источников не влияли на интерфейс результата.
1. Изменятся ли имена результата, если поменять ветви UNION местами?
Да. Имена берутся из первой ветви, поэтому перестановка ветвей может изменить заголовки столбцов. Сами значения могут остаться теми же, но типы и правила преобразования также следует проверить.
2. Что произойдёт, если ветви имеют одинаковое число столбцов, но разные имена?
Имена будут взяты из первой ветви, а значения сопоставятся по позициям. SQL не ищет соответствия по одинаковым названиям и не проверяет, что смысл столбцов совпадает, поэтому ошибку в порядке выражений СУБД может не обнаружить.
3. Как явно задать имена результата объединения внутри CTE?
У CTE можно задать список имён столбцов после его имени. Тогда внешний запрос будет использовать эти имена независимо от псевдонимов в SELECT внутри CTE. Однако количество имён должно соответствовать количеству столбцов результата CTE.