Alias ​​de columna de referencia en la misma lista SELECT

27

Estoy convirtiendo un viejo sistema basado en MS-Access a PostgreSQL. En Access, los campos formados en SELECT podrían usarse como partes de ecuaciones 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;

Cuando hago esto en PostgreSQL, Postgres arroja un error:

ERROR: la columna "percent_water" no existe.

Así es como puedo solucionarlo, seleccionando una sub-selección:

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;

¿Hay algún tipo de acceso directo como en el primer bloque de código para evitar la anidación complicada? También podría decir 100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100, pero este es solo un pequeño ejemplo de lo que es un sistema matemático mucho más grande en mi código, con docenas de fragmentos matemáticos más complejos apilados uno encima del otro. Prefiero hacerlo lo más limpio posible sin repetirme.

wizpig64
fuente

Respuestas:

24

A veces es inconveniente, pero es un comportamiento estándar de SQL y evita ambigüedades. No puede hacer referencia a alias de columna en la misma SELECTlista.

Hay opciones de sintaxis más cortas:

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;

Y puede usar una LATERALunión en 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;

Agregué NULLIF()para defenderme de los errores de división por cero.

Erwin Brandstetter
fuente
2
Hola. ¿Puede extender su respuesta con un ejemplo de las ambigüedades que previene el estándar SQL?
Eugen Konkov
4

Llegué a algo como esto al migrar una consulta Netezza de más de 500 líneas (también conocido como Postgres modificado) a SQL Server. En Netezza, se permitió que el alias de columna calculado se usara como un valor en las referencias posteriores.

Mi trabajo fue usar CROSS APPLY con una subconsulta correlacionada. Lo bueno de esto es que las numerosas referencias al alias de columna en la consulta original no necesitaban modificarse en absoluto.

Usando la consulta desde el OP, el CROSS APPLYmétodo se vería así:

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
fuente
1
CROSS APPLY(y OUTER APPLY) es la forma en que SQL Server escribe LATERALsubconsultas.
ypercubeᵀᴹ
44
No hay cross applyen Postgres. Postgres se adhiere al estándar y a los usos cross join lateral.
a_horse_with_no_name