2009-07-30 4 views
34

J'ai une colonne qui ressemble à quelque chose comme ceci:SQL GROUP BY CASE avec fonction d'agrégation

CASE 
    WHEN col1 > col2 THEN SUM(col3*col4) 
    ELSE 0 
END AS some_product 

Et je voudrais le mettre dans ma clause GROUP BY, mais cela semble causer des problèmes parce qu'il ya une fonction d'agrégation en colonne. Existe-t-il un moyen de GROUP BY un alias de colonne tel que some_product dans ce cas, ou dois-je mettre cela dans une sous-requête et un groupe sur cela?

Répondre

41

Je pense que vous ne voulez pas vraiment GROUP BY some_product.

La réponse à: « ? Y at-il un moyen de GROUP BY un alias de colonne telle que some_product dans ce cas, ou dois-je mettre cela dans une sous-requête et le groupe sur ce » est: Vous ne pouvez pas GROUP BY un alias de colonne.

La clause SELECT, dans laquelle des alias de colonne sont affectés, n'est pas traitée avant la clause GROUP BY. Une vue en ligne ou une expression de table commune (CTE) pourrait être utilisée pour rendre les résultats disponibles pour le regroupement.

vue Inline:

select ... 
from (select ... , CASE WHEN col1 > col2 THEN SUM(col3*col4) ELSE 0 END AS some_product 
    from ... 
    group by col1, col2 ...) T 
group by some_product ... 

CTE:

with T as (select ... , CASE WHEN col1 > col2 THEN SUM(col3*col4) ELSE 0 END AS some_product 
    from ... 
    group by col1, col2 ...) 
select ... 
from T 
group by some_product ... 
+1

Ceci est un bon exemple de comment utiliser un CTE . –

1

Si vous regroupez par une autre valeur, au lieu de ce que vous avez,

écrire comme

Sum(CASE WHEN col1 > col2 THEN SUM(col3*col4) ELSE 0 END) as SumSomeProduct 

Si, Otoh, vous voulez group By l'expression interne, (col3*col4) puis

écrivez le group By pour correspondre à l'expression sans le SUM ...

Select Sum(Case When col1 > col2 Then col3*col4 Else 0 End) as SumSomeProduct 
From ... 

Group By Case When col1 > col2 Then col3*col4 Else 0 End 

Enfin, si vous voulez groupe par l'ensemble réel

Select SumSomeProduct, Count(*), <other aggregate functions> 
From (Select <other columns you are grouping By>, 
     Sum(Case When col1 > col2 
      Then col3*col4 Else 0 End) as SumSomeProduct 
     From Table 
     Group By <Other Columns>) As Z 
Group by SumSomeProduct 
+0

Vous regroupez * sur * un regroupement. Pas * sur * le groupement. – gbn

+0

Celui qui a upvoted, c'est faux. Essayez quelque chose de similaire vous-même ... "donnez-moi la somme de 2 valeurs multipliées, groupées par 2 autres valeurs, et aussi le groupe sur l'ensemble de mon groupe". – gbn

+0

Après l'édition de Charles: votre requête intérieure ne reviendra jamais qu'une seule ligne, rendant votre groupement externe vide de sens ... – gbn

27

Alors que Shannon's answer est techniquement correct, il semble exagéré.

La solution simple est que vous devez mettre votre somme en dehors de l'instruction case. Cela devrait faire l'affaire:

sum(CASE WHEN col1 > col2 THEN col3*col4 ELSE 0 END) AS some_product 

Fondamentalement, votre ancien code SQL indique pour exécuter le sum(X*Y) pour chaque ligne individuellement (en laissant chaque ligne avec sa propre réponse qui ne peuvent pas être regroupés).

La ligne de code que j'ai écrite prend le produit de somme, ce que vous voulez.

+0

Y a-t-il une raison pour laquelle vous ne voudriez pas utiliser cette méthode plutôt que la réponse de Shannon impliquant un CTE? Merci – Gareth

+0

Pour les déclarations de cas généraux, vous voudriez utiliser la réponse de Shannon. Celui-ci repose sur des sommes de 0 étant 0. – coberlin