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
etGROUP BY
clauses, mais pas dansWHERE
ouHAVING
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 queGROUP 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.