10.5. UNION
, CASE
и связанные конструкции
SQL-конструкция UNION
взаимодействует с системой типов, так как ей приходится объединять значения возможно различных типов в единый результирующий набор. Алгоритм разрешения типов при этом применяется независимо к каждому выходному столбцу запроса. Конструкции INTERSECT
и EXCEPT
сопоставляют различные типы подобно UNION
. По такому же алгоритму сопоставляют типы выражений и определяют тип своего результата некоторые другие конструкции, включая CASE
, ARRAY
, VALUES
и функции GREATEST
и LEAST
.
Разрешение типов для UNION
, CASE
и связанных конструкций
Если все данные одного типа и это не тип
unknown
, выбрать его.Если тип данных — домен, далее считать их типом базовый тип домена. [1]
Если все данные типа
unknown
, выбрать для результата типtext
(предпочитаемый для категории string). В противном случае значенияunknown
игнорируются.Если известные типы входных данных оказываются не из одной категории, констатировать неудачу.
Выбрать первый известный тип данных в качестве типа-кандидата, затем рассмотреть все остальные известные типы данных, слева направо. [2] Если ранее выбранный тип может быть неявно преобразован к другому типу, но преобразовать второй в первый нельзя, выбрать второй тип в качестве нового кандидата. Затем продолжать рассмотрение последующих данных. Если на любом этапе этого процесса выбирается предпочитаемый тип, следующие данные больше не рассматриваются.
Привести все данные к окончательно выбранному типу. Констатировать неудачу, если неявное преобразование из типа входных данных в выбранный тип невозможно.
Ниже это проиллюстрировано на примерах.
Пример 10.10. Разрешение типов с частичным определением в Union
SELECT text 'a' AS "text" UNION SELECT 'b'; text ------ a b (2 rows)
В данном случае константа 'b'
неизвестного типа будет преобразована в тип text
.
Пример 10.11. Разрешение типов в простом объединении
SELECT 1.2 AS "numeric" UNION SELECT 1; numeric --------- 1 1.2 (2 rows)
Константа 1.2
имеет тип numeric
и целочисленное значение 1
может быть неявно приведено к типу numeric
, так что используется этот тип.
Пример 10.12. Разрешение типов в противоположном объединении
SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL); real ------ 1 2.2 (2 rows)
Здесь значение типа real
нельзя неявно привести к integer
, но integer
можно неявно привести к real
, поэтому типом результата объединения будет real
.
Пример 10.13. Разрешение типов во вложенном объединении
SELECT NULL UNION SELECT NULL UNION SELECT 1; ERROR: UNION types text and integer cannot be matched
Эта ошибка возникает из-за того, что Postgres Pro воспринимает множественные UNION
как пары с вложенными операциями, то есть как запись
(SELECT NULL UNION SELECT NULL) UNION SELECT 1;
Внутренний UNION
разрешается как выдающий тип text
, согласно правилам, приведённым выше. Затем внешний UNION
получает на вход типы text
и integer
, что и приводит к показанной ошибке. Эту проблему можно устранить, сделав так, чтобы у самого левого UNION
минимум с одной стороны были данные желаемого типа результата.
Операции INTERSECT
и EXCEPT
также разрешаются по парам. Однако остальные конструкции, описанные в этом разделе, рассматривают все входные данные сразу.
[1] Так же, как домены воспринимаются при выборе операторов и функций, доменные типы могут сохраняться в конструкции UNION
или подобной, если пользователь позаботится о том, чтобы все входные данные приводились к этому типу явно или неявно. В противном случае будет использоваться базовый тип домена.
[2] По историческим причинам в конструкции CASE
выражение в предложении ELSE
(если оно есть) обрабатывается как «первое», а предложения THEN
рассматриваются после. Во всех остальных случаях, «слева направо» означает порядок, в котором выражения действительно идут в тексте запроса.