web-dev-qa-db-fra.com

Comment réutiliser une colonne de résultat dans une expression pour une autre colonne de résultat

Exemple:

SELECT
   (SELECT SUM(...) FROM ...) as turnover,
   (SELECT SUM(...) FROM ...) as cost,
   turnover - cost as profit

Bien sûr, cela n’est pas valide (du moins dans Postgres), mais comment obtenir la même chose dans une requête sans réécrire la sous-requête deux fois?

43
Wernight

Ainsi:

SELECT
   turnover,
   cost,
   turnover - cost as profit
from (
   (SELECT SUM(...) FROM ...) as turnover,
   (SELECT SUM(...) FROM ...) as cost
   ) as partial_sums
42
Denis de Bernardy

Vous pouvez réutiliser la requête comme ceci:

WITH 
  TURNOVER AS (
    SELECT SUM(...) FROM ...)
  ),
  COST AS(
    SELECT SUM(...) FROM ...
  )

SELECT *
FROM(
 SELECT
   TURNOVER.sum as SUM_TURNOVER
 FROM
 TURNOVER,COST
 WHERE ....
) AS a

Ceci est équivalent à:

SELECT *
FROM(
 SELECT
   TURNOVER.sum as SUM_TURNOVER
 FROM
 (
   SELECT SUM(...) FROM ...)
 )AS TURNOVER,
 (
   SELECT SUM(...) FROM ...
 )AS COST
 WHERE ....
) AS a

Il y a un point à noter ici. La première méthode est plus lisible et réutilisable, mais la deuxième peut être plus rapide, car la base de données peut choisir un meilleur plan pour elle.

12
Alex Calugarescu

La clause "with" de SQL pourrait peut-être aider, comme présenté ici http://orafaq.com/node/1879 (d’autres bases de données telles que Postgres le font aussi, pas seulement Oracle).

6
andrers52

En fait, j’ai beaucoup travaillé sur ce sujet et j’ai heurté de nombreux murs de briques, mais j’ai finalement trouvé une réponse - plutôt un bidouillage - mais cela fonctionnait très bien et réduisait le temps de lecture de mes requêtes de 90% ...

Ainsi, plutôt que de dupliquer plusieurs fois la requête corrélée pour récupérer plusieurs colonnes de la sous-requête, je viens d’utiliser Concat toutes les valeurs que je souhaite renvoyer dans un varchar séparé par des virgules, puis de les dérouler à nouveau dans l’application ...

Donc au lieu de

select a,b,
(select x from bigcorrelatedsubquery) as x,
(select y from bigcorrelatedsubquery) as y,
(select z from bigcorrelatedsubquery) as z
from outertable

Je fais maintenant

select a,b,
(select convert(varchar,x)+','+convert(varchar,x)+','+convert(varchar,x)+',' 
from bigcorrelatedsubquery) from bigcorrelatedquery) as xyz
from outertable
group by country

J'ai maintenant les trois valeurs «scalaires» corrélées dont j'avais besoin mais je n'avais qu'à exécuter la sous-requête corrélée une fois au lieu de trois fois.

4
bhealy
SELECT turnover, cost, turnover - cost
FROM
(
SELECT
(SELECT ...) as turnover,
(SELECT ...) as cost
) as Temp
4
Eric.K.Yung

Je pense que ce qui suit fonctionnera:

SELECT turnover, cost, turnover-cost as profit FROM
   (SELECT 1 AS FAKE_KEY, SUM(a_field) AS TURNOVER FROM some_table) a
INNER JOIN
   (SELECT 1 AS FAKE_KEY, SUM(a_nother_field) AS COST FROM some_other_table) b
USING (FAKE_KEY);

Non testé sur les animaux - vous serez le premier! :-)

Partager et profiter.

3
Bob Jarvis

Utilisez une application en croix ou externe.

SELECT
  Calc1.turnover,
  Calc2.cost,
  Calc3.profit
from
   cross apply ((SELECT SUM(...) as turnover FROM ...)) as Calc1
   cross apply ((SELECT SUM(...) as cost FROM ...)) as Calc2

   /*
     Note there is no from Clause in Calc 3 below.
     This is how you can "stack" formulas like in Excel.
     You can return any number of columns, not just one.
   */
   cross apply (select Calc1.turnover - Calc2.cost as profit) as Calc3
0
William Egge

c'est assez vieux mais j'ai rencontré ce problème et vu ce post mais je n'ai pas réussi à résoudre mon problème en utilisant les réponses données donc je suis finalement arrivé à cette solution: 

si votre requête est:

SELECT
   (SELECT SUM(...) FROM ...) as turnover,
   (SELECT SUM(...) FROM ...) as cost,
   turnover - cost as profit

vous pouvez le transformer en une sous-requête puis utiliser les champs tels que:

SELECT *,(myFields.turnover-myFields.cost) as profit 
FROM
(      
SELECT
       (SELECT SUM(...) FROM ...) as turnover,
       (SELECT SUM(...) FROM ...) as cost

) as myFields

je ne suis pas tout à fait sûr que ce soit une mauvaise façon de faire les choses, mais en termes de performances, cela me semble correct d'interroger des enregistrements 224,000 prend 1,5 seconde.

0
Niklas