Alias ​​da coluna de referência na mesma lista SELECT

27

Estou convertendo um antigo sistema baseado no MS-Access para PostgreSQL. No Access, os campos criados em SELECTs podem ser usados ​​como partes de equações para campos posteriores, como este:

SELECT
    samples.id,
    samples.wet_weight / samples.dry_weight - 1 AS percent_water,
    100 * percent_water AS percent_water_100
FROM samples;

Quando faço isso no PostgreSQL, o Postgres lança um erro:

ERRO: a coluna "percent_water" não existe.

Veja como posso solucionar isso, selecionando uma sub-seleção:

SELECT
    s1.id,
    s1.percent_water,
    100 * s1.percent_water AS percent_water_100
FROM (
    SELECT
        samples.id,
        samples.wet_weight / samples.dry_weight - 1 AS percent_water
    FROM samples
    ) s1;

Existe algum tipo de atalho como no primeiro bloco de código para contornar aninhamentos complicados? Eu também poderia dizer 100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100, mas este é apenas um pequeno exemplo do que é um sistema de matemática muito maior acontecendo no meu código, com dezenas de bits de matemática mais complexos empilhados um sobre o outro. Eu preferiria fazer o mais limpo possível sem me repetir.

wizpig64
fonte

Respostas:

24

Às vezes, é inconveniente, mas é um comportamento padrão do SQL e evita ambiguidades. Você não pode fazer referência a aliases de coluna na mesma SELECTlista.

Existem opções de sintaxe mais curtas:

SELECT s.*, s.percent_water * 100 AS percent_water_100
FROM  (
   SELECT id, wet_weight / NULLIF(dry_weight - 1, 0) AS percent_water
   FROM   samples
   ) s;

E você pode usar uma LATERALjunção no Postgres 9.3+:

SELECT s.id, s1.percent_water
     , s1.percent_water * 100 AS percent_water_100
FROM   samples s
     , LATERAL (SELECT s.wet_weight / NULLIF(s.dry_weight - 1, 0) AS percent_water) s1;

Eu adicionei NULLIF()para defender contra erros de divisão por zero.

Erwin Brandstetter
fonte
2
Oi. Você pode estender sua resposta com um exemplo que as ambigüidades que o padrão SQL impede?
Eugen Konkov
4

Eu bati em algo assim migrando uma consulta Netezza com mais de 500 linhas (também conhecida como Postgres modificado) para o SQL Server. No Netezza, o alias da coluna computada foi permitido como valor nas referências posteriores.

Minha solução foi usar o CROSS APPLY com uma subconsulta correlacionada. A vantagem disso é que as inúmeras referências ao alias da coluna na consulta original não precisaram ser alteradas.

Usando a consulta do OP, o CROSS APPLYmétodo seria algo como:

SELECT
    s.id,
    x.percent_water,
    100 * x.percent_water AS percent_water_100
FROM samples AS s
CROSS APPLY (SELECT s.wet_weight / s.dry_weight - 1 AS percent_water ) x ;
D Turpin
fonte
11
CROSS APPLY(e OUTER APPLY) é a maneira de escrever LATERALsubconsultas do SQL Server .
precisa saber é o seguinte
4
Não existe cross applyno Postgres. O Postgres segue os padrões e usos cross join lateral.
a_horse_with_no_name