Alias ​​de colonne de référence dans la même liste SELECT


27

Je convertis un ancien système basé sur MS-Access en PostgreSQL. Dans Access, les champs constitués dans SELECT peuvent être utilisés comme parties d'équations pour des champs ultérieurs, comme ceci:

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

Quand je fais cela dans PostgreSQL, Postgres lance une erreur:

ERREUR: la colonne "percent_water" n'existe pas.

Voici comment je peux contourner ce problème en sélectionnant une sous-sélection:

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-t-il une sorte de raccourci comme dans le premier bloc de code pour contourner l'imbrication compliquée? Je pourrais également dire 100 * (samples.wet_weight / samples.dry_weight - 1) AS percent_water_100, mais ce n'est qu'un petit exemple de ce qui est un système de mathématiques beaucoup plus vaste dans mon code, avec des dizaines de bits de mathématiques plus complexes empilés les uns sur les autres. Je préfère faire le plus proprement possible sans me répéter.

Réponses:


24

C'est parfois gênant, mais c'est un comportement standard SQL et cela évite les ambiguïtés. Vous ne pouvez pas référencer des alias de colonne dans la même SELECTliste.

Il existe des options de syntaxe plus courtes:

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;

Et vous pouvez utiliser une LATERALjointure dans 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;

J'ai ajouté NULLIF()pour me défendre contre les erreurs de division par zéro.


2
Salut. Pouvez-vous étendre votre réponse par un exemple des ambiguïtés que le standard SQL empêche?
Eugen Konkov

4

J'ai frappé quelque chose comme ça en migrant une requête Netezza de plus de 500 lignes (aka Postgres modifié) vers SQL Server. Dans Netezza, l'alias de colonne calculé pouvait être utilisé comme valeur dans les références en aval.

Mon travail consistait à utiliser CROSS APPLY avec une sous-requête corrélée. La beauté de celui-ci est que les nombreuses références à l'alias de colonne dans la requête d'origine n'avaient pas du tout besoin d'être modifiées.

En utilisant la requête de l'OP, la CROSS APPLYméthode ressemblerait à quelque chose comme:

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 ;

1
CROSS APPLY(et OUTER APPLY) est la façon dont SQL Server écrit les LATERALsous-requêtes.
ypercubeᵀᴹ

4
Il n'y cross applyen a pas à Postgres. Postgres s'en tient à la norme et utilise cross join lateral.
a_horse_with_no_name
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.