PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Instruction GROUP BY + CASE

Votre requête fonctionnerait déjà - sauf que vous rencontrez des conflits de nom ou que vous confondez simplement la colonne de sortie (le CASE expression) avec colonne source result , qui a un contenu différent.

...
GROUP BY model.name, attempt.type, attempt.result
...

Vous devez GROUP BY votre CASE expression au lieu de votre colonne source :

...
GROUP BY model.name, attempt.type
       , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END
...

Ou fournissez un alias de colonne qui est différent de tout nom de colonne dans le FROM list - sinon cette colonne est prioritaire :

SELECT ...
     , CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END AS result1
...
GROUP BY model.name, attempt.type, result1
...

Le standard SQL est assez particulier à cet égard. Citant le manuel ici :

Le nom d'une colonne de sortie peut être utilisé pour faire référence à la valeur de la colonne dans ORDER BY et GROUP BY clauses, mais pas dans WHERE ou HAVING clauses ; là, vous devez écrire l'expression à la place.

Et :

Si un ORDER BY expression est un nom simple qui correspond à la fois à un nom de colonne de sortie et à un nom de colonne d'entrée, ORDER BY l'interprétera comme le nom de la colonne de sortie. C'est le contraire du choix que GROUP BY fera dans la même situation. Cette incohérence est faite pour être compatible avec le standard SQL.

Gras c'est moi qui souligne.

Ces conflits peuvent être évités en utilisant des références positionnelles (nombres ordinaux) dans GROUP BY et ORDER BY , faisant référence aux éléments dans le SELECT liste de gauche à droite. Voir la solution ci-dessous.
L'inconvénient est que cela peut être plus difficile à lire et vulnérable aux modifications dans le SELECT liste (on pourrait oublier d'adapter les références de position en conséquence).

Mais vous ne le faites pas il faut ajouter la colonne day au GROUP BY clause, tant qu'elle contient une valeur constante (CURRENT_DATE-1 ).

Réécrit et simplifié avec une syntaxe JOIN appropriée et des références de position, il pourrait ressembler à ceci :

SELECT m.name
     , a.type
     , CASE WHEN a.result = 0 THEN 0 ELSE 1 END AS result
     , CURRENT_DATE - 1 AS day
     , count(*) AS ct
FROM   attempt    a
JOIN   prod_hw_id p USING (hard_id)
JOIN   model      m USING (model_id)
WHERE  ts >= '2013-11-06 00:00:00'  
AND    ts <  '2013-11-07 00:00:00'
GROUP  BY 1,2,3
ORDER  BY 1,2,3;

Notez également que j'évite le nom de colonne time . C'est un mot réservé et ne doit jamais être utilisé comme identifiant. De plus, votre "heure" est évidemment un timestamp ou date , donc c'est plutôt trompeur.