web-dev-qa-db-fra.com

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

Je convertis un ancien système basé sur MS-Access en PostgreSQL. Dans Access, les champs créé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 aussi simplement 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 mathématique beaucoup plus vaste dans mon code, avec des dizaines de bits 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.

32
wizpig64

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 liste SELECT.

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 jointure LATERAL 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.

27
Erwin Brandstetter

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, le CROSS APPLY la méthode ressemblerait à ceci:

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 ;
5
D Turpin