Как определяется тип каждого столбца результата UNION, если соответствующие столбцы ветвей имеют разные типы?
Для каждой позиции столбца SQL должен определить общий тип, совместимый с типами соответствующих выражений во всех ветвях UNION. Если типы совместимы, СУБД применяет правила приведения типов; если общего типа нет, запрос завершается ошибкой. Точные правила выбора общего типа зависят от конкретной СУБД, поэтому явное приведение типов делает контракт запроса предсказуемым.
Операции UNION, INTERSECT и EXCEPT объединяют отношения с одинаковой структурой: у ветвей должно быть одинаковое число столбцов, а соответствующие позиции должны быть типово совместимы. Это позволяет рассматривать результат как единый набор данных, несмотря на разные источники строк.
Проблема возникает потому, что SQL является типизированным языком. Например, целое число и число с фиксированной точностью могут быть приведены к общему числовому типу, но текст и дата обычно не имеют универсального неявного типа.
Сопоставление выполняется по позиции, а не по имени столбца. Первый столбец первой ветви сопоставляется с первым столбцом второй ветви, второй — со вторым и так далее.
Если разработчик полагается на неявное приведение, результат может зависеть от правил конкретной СУБД: измениться тип результата, точность чисел или поведение дальнейших операций. Особенно опасно это при добавлении третьей ветви, параметра неизвестного типа или значения NULL без явного типа.
Сначала проверяется структурная совместимость: число столбцов во всех ветвях должно совпадать. Затем для каждой позиции отдельно определяется тип результата на основе типов выражений этой позиции.
Например, в таком запросе обе ветви формируют один столбец, но явно приводят его к единому типу:
UNION ALL сохраняет все строки, а UNION дополнительно удаляет дубликаты. Выбор между ними не меняет принцип определения типов, но удаление дубликатов требует сравнения значений уже после приведения к типам результата.
Имена столбцов результата — отдельный вопрос: обычно они берутся из первой ветви, но это не определяет типы последующих ветвей. Алиасы во второй ветви не переименовывают соответствующий столбец результата.
Не следует считать, что SQL всегда выбирает тип первой ветви. Конкретный алгоритм разрешения типов и набор неявных приведений определяются СУБД. Надёжный переносимый подход — явно приводить соответствующие выражения к одному типу во всех ветвях, особенно для денежных значений, дат, строк разной длины и NULL.
Отчёт объединяет суммы из двух источников: один источник хранит их как целые числа, другой — как числа с дробной частью. Вариант с неявным приведением короче, но оставляет выбор общего типа СУБД и может привести к неожиданной точности или ошибке при расширении запроса.
Вариант с явным CAST немного увеличивает текст запроса, зато фиксирует точность и облегчает проверку схемы результата. Для финансового отчёта выбирают именно его, потому что предсказуемый тип важнее краткости. В результате все ветви возвращают одинаковый тип, а потребители отчёта получают стабильный контракт данных.
Нет, соответствие определяется позицией. Если первая ветвь возвращает идентификатор и описание, а вторая — описание и идентификатор, SQL не переставит столбцы по именам. Запрос может успешно выполниться, если типы совместимы, но данные окажутся семантически перепутаны. Поэтому порядок выражений нужно явно согласовывать во всех ветвях.
NULL не содержит конкретного значения, но для выражения всё равно должен быть определён тип в контексте операции. СУБД может вывести его из другой ветви, однако правила различаются, а при нескольких ветвях или неоднозначном контексте запрос может завершиться ошибкой. Явное приведение NULL к ожидаемому типу устраняет неоднозначность.
Само удаление дубликатов не выбирает другой тип: сначала формируется тип каждой позиции результата, затем значения сравниваются в рамках этого типа. Но сравнение после приведения может отличаться от сравнения исходных значений, а некоторые типы вообще могут быть несовместимы с операцией удаления дубликатов в конкретной СУБД. Поэтому совместимость для UNION нужно оценивать не только по возможности привести значения, но и по поддержке сравнения результирующего типа.