10.5. UNION, CASE e construções relacionadas #

As construções SQL UNION devem corresponder a tipos de dados possivelmente diferentes para se tornar um único conjunto de resultados. O algoritmo de resolução é aplicado em separado a cada coluna da saída de uma consulta de união. As construções INTERSECT e EXCEPT resolvem tipos de dados diferentes da mesma maneira que UNION. Algumas outras construções, incluindo CASE, ARRAY, VALUES, e as funções GREATEST e LEAST, usam um algoritmo idêntico para corresponder às expressões de seus componentes e selecionar um tipo de dados de resultado.

Resolução de tipo de dados para UNION, CASE e construções relacionadas

  1. Se todas as entradas forem do mesmo tipo de dados, e não forem do tipo de dados unknown, resolva como este tipo de dados.

  2. Se alguma entrada for de um tipo de dados de domínio, trate-a como sendo do tipo de dados base do domínio para todas as etapas subsequentes. [95]

  3. Se todas as entradas forem do tipo de dados unknown, resolva como tipo de dados text (o tipo de dados preferido da categoria cadeia de caracteres). Caso contrário, as entradas unknown serão ignoradas para os propósitos das regras restantes.

  4. Se as entradas diferentes de unknown não forem todas da mesma categoria de tipo de dados, falhe.

  5. Selecione o primeiro tipo de dados de entrada não desconhecido como tipo de dados candidato e, em seguida, considere cada outro tipo de dados de entrada não desconhecido, da esquerda para a direita. [96] Se o tipo de dados candidato puder ser convertido implicitamente para o outro tipo de dados, mas não o contrário, selecione o outro tipo de dados como o novo tipo de dados candidato. Em seguida, continue considerando as entradas restantes. Se, em qualquer estágio deste processo, for selecionado um tipo de dados preferido, pare de considerar as entradas adicionais.

  6. Converta todas as entradas para o tipo de dados candidato final. Falhe caso não haja uma conversão implícita de um determinado tipo de dados de entrada para o tipo de dados candidato.

Seguem alguns exemplos.

Exemplo 10.11. Resolução de tipo de dados com tipos de dados subespecificados em uma união

SELECT text 'a' AS "text" UNION SELECT 'b';

 text
------
 a
 b
(2 linhas)

Aqui, o literal de tipo de dados desconhecido 'b' será resolvido para o tipo de dados text.


Exemplo 10.12. Resolução de tipo de dados em uma união simples

SELECT 1.2 AS "numeric" UNION SELECT 1;

 numeric
---------
       1
     1.2
(2 linhas)

O literal 1.2 é do tipo de dados numeric, e o valor integer 1 pode ser convertido implicitamente em numeric, então este tipo de dados é usado.


Exemplo 10.13. Resolução de tipo de dados em uma união transposta

SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL);

 real
------
    1
  2.2
(2 linhas)

Aqui, como o tipo de dados real não pode ser convertido implicitamente em integer, mas integer pode ser convertido implicitamente em real, o tipo de dados do resultado da união é resolvido como real.


Exemplo 10.14. Resolução de tipo de dados em uma união aninhada

SELECT NULL UNION SELECT NULL UNION SELECT 1;
ERRO:  tipos de dados no UNION text e integer não podem corresponder
LINHA 1: SELECT NULL UNION SELECT NULL UNION SELECT 1;
                                                    ^

Esta falha ocorre, porque o PostgreSQL trata vários UNION como sendo um aninhamento de operações em pares; ou seja, esta entrada é idêntica a

(SELECT NULL UNION SELECT NULL) UNION SELECT 1;

O UNION interno é resolvido como emitindo o tipo de dados text, segundo as regras fornecidas acima. Então o UNION externo tem entradas dos tipos de dados text e integer, levando ao erro observado. O problema pode ser corrigido garantindo que o UNION mais à esquerda tenha pelo menos uma entrada do tipo de dados do resultado desejado.

As operações INTERSECT e EXCEPT também são resolvidos aos pares. Entretanto, as outras construções descritas nesta seção consideram todas as suas entradas em uma etapa de resolução.




[95] Um pouco como o tratamento de entradas de domínio para operadores e funções, este comportamento permite que um tipo de dados de domínio seja preservado por meio de uma UNION ou construção semelhante, desde que o usuário tenha o cuidado de garantir que todas as entradas sejam implícitas ou explicitamente deste exato tipo de dados. Caso contrário, o tipo de dados base do domínio será usado.

[96] Por motivos históricos, CASE trata sua cláusula ELSE (se houver) como a primeira entrada, com as cláusulas THEN consideradas depois. Em todos os outros casos, da esquerda para a direita significa a ordem em que as expressões aparecem no texto da consulta.