10.5. UNION, CASE и связанные конструкции

SQL-конструкция UNION взаимодействует с системой типов, так как ей приходится объединять значения возможно различных типов в единый результирующий набор. Алгоритм разрешения типов при этом применяется независимо к каждому отдельному столбцу запроса. Подобным образом различные типы сопоставляются при выполнении INTERSECT и EXCEPT сопоставляют различные типы подобно UNION. По такому же алгоритму сопоставляют типы выражений и определяют тип своего результата конструкции CASE, ARRAY, VALUES, GREATEST и LEAST.

Разрешение типов для UNION, CASE и связанных конструкций

  1. Если все данные одного типа и это не тип unknown, выбрать его.

  2. Если тип данных — домен, далее считать их типом базовый тип домена. [11]

  3. Если все данные типа unknown, выбрать для результата тип text (предпочитаемый для категории string). В противном случае значения unknown для остальных правил игнорируются.

  4. Если известные типы входных данных оказываются не из одной категории, констатировать неудачу.

  5. Выбрать первый известный предпочитаемый тип из этой категории, если такой есть.

  6. В противном случае выбрать последний известный тип, в который можно неявно преобразовать все данные предшествующих известных типов. (Такой тип есть всегда, в крайнем случае этому условию удовлетворяет первый тип.)

  7. Привести все данные к выбранном типу. Констатировать неудачу, если для каких-либо данных преобразование в этот тип невозможно.

Ниже это проиллюстрировано на примерах.

Пример 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

Эта ошибка возникает из-за того, что PostgreSQL воспринимает множественные UNION как пары с вложенными операциями, то есть как запись

(SELECT NULL UNION SELECT NULL) UNION SELECT 1;

Внутренний UNION разрешается как выдающий тип text, согласно правилам, приведённым выше. Затем внешний UNION получает на вход типы text и integer, что и приводит к показанной ошибке. Эту проблему можно устранить, сделав так, чтобы у самого левого UNION минимум с одной стороны были данные желаемого типа результата.

Операции INTERSECT и EXCEPT также разрешаются по парам. Однако остальные конструкции, описанные в этом разделе, рассматривают все входные данные сразу.




[11] Так же, как домены воспринимаются при выборе операторов и функций, доменные типы могут сохраняться в конструкции UNION или подобной, если пользователь позаботится о том, чтобы все входные данные приводились к этому типу явно или неявно. В противном случае предпочтение будет отдано базовому типу домена.