web-dev-qa-db-fra.com

PostgreSQL: utiliser une colonne calculée dans la même requête

J'ai du mal à utiliser une colonne calculée en postgres. Un code similaire qui fonctionne en SQL est donné ci-dessous, est-il possible de le recréer dans PostgreSQL?

select cost_1, quantity_1, cost_2, quantity_2, 
      (cost_1 * quantity_1) as total_1,
      (cost_2 * quantity_2) as total_2,
      (calculated total_1 + calculated total_2) as total_3
from data;

Dans PostgreSQL, un code similaire renvoie l'erreur qui:

les colonnes total_1 et total_2 n'existent pas.

41
user1146150

Vous devez encapsuler l'instruction SELECT dans une table dérivée afin de pouvoir accéder à l'alias de colonne:

select cost1,
       quantity_1,
       cost_2,
       quantity_2
       total_1 + total_2 as total_3
from (
    select cost_1, 
           quantity_1, 
           cost_2, 
           quantity_2, 
           (cost_1 * quantity_1) as total_1,
           (cost_2 * quantity_2) as total_2
    from data
) t

Il n'y aura aucune pénalité de performance à ce sujet.

(Je suis vraiment surpris que votre instruction SQL d'origine s'exécute dans un SGBD)

44

Si vous n'aimez pas encapsuler la requête entière avec une requête externe, vous pouvez utiliser LATERAL pour calculer l'intermédiaire total_1 et total_2:

SELECT cost_1, quantity_1, cost_2, quantity_2, total_1, total_2,
       total_1 + total_2 AS total_3
FROM data
,LATERAL(SELECT cost_1 * quantity_1, cost_2 * quantity_2) AS s1(total_1,total_2);

Démo DBFiddle

Production:

╔═════════╦═════════════╦═════════╦═════════════╦══════════╦══════════╦═════════╗
║ cost_1  ║ quantity_1  ║ cost_2  ║ quantity_2  ║ total_1  ║ total_2  ║ total_3 ║
╠═════════╬═════════════╬═════════╬═════════════╬══════════╬══════════╬═════════╣
║      1  ║          2  ║      3  ║          4  ║       2  ║      12  ║      14 ║
║      3  ║          5  ║      7  ║          9  ║      15  ║      63  ║      78 ║
║     10  ║          5  ║     20  ║          2  ║      50  ║      40  ║      90 ║
╚═════════╩═════════════╩═════════╩═════════════╩══════════╩══════════╩═════════╝
27
Lukasz Szozda

En règle générale, il y a deux choses que vous devez savoir sur la clause SELECT:

  • Bien qu'il soit écrit en premier , il est évalué en dernier , à l'exception du ORDER BY clause. C'est pourquoi vous ne pouvez pas utiliser de champs calculés ou d'alias dans une autre clause (en particulier la clause WHERE) sauf dans le ORDER BY clause.
  • Les calculs dans la clause SELECT sont effectués en parallèle , ou au moins sont traités comme s'ils l'étaient. C'est pourquoi vous ne pouvez pas utiliser un calcul dans le cadre d'un autre.

Donc, la réponse courte est que vous ne pouvez pas, et c'est par conception.

L'exception notable à cela est Microsoft Access, où vous pouvez en effet utiliser des calculs dans les colonnes suivantes et les clauses WHERE. Cependant, bien que cela soit pratique, ce n'est pas vraiment un avantage: ne pas suivre les principes ci-dessus est moins efficace. Mais c'est OK pour les bases de données légères, pour lesquelles Access est censé être utilisé.

Si vous voulez vraiment réutiliser les résultats calculés, vous aurez besoin d'une requête distincte, soit sous la forme d'une sous-requête, soit en tant qu'expression de table commune. Les CTE sont beaucoup plus faciles à utiliser, car ils sont plus lisibles.

Modifier

Sans changer le point de la réponse originale, j'ai pensé que je pourrais ajouter que je pense que cette explication est peut-être un peu mesquin.

Les SGBD modernes mettent beaucoup d'efforts dans la planification et l'optimisation des requêtes, il n'est donc plus correct, si jamais, que la requête est réellement exécutée dans un ordre particulier. Pour autant que je sache, il n'y a aucune raison technique pour laquelle l'optimiseur ne pouvait pas anticiper et incorporer les résultats calculés dans l'analyse de la requête, même s'il est seulement de substituer des expressions.

Tant pis …

11
Manngo
select cost_1, quantity_1, cost_2, quantity_2, 
      cost_1 * quantity_1 as total_1,
      cost_2 * quantity_2 as total_2,
      (cost_1 * quantity_1 + cost_2 * quantity_2) as total_3
from data;
0
Sarah