J'ai une requête de travail qui regroupe des données par modèle matériel et un résultat, mais le problème est qu'il existe de nombreux "résultats" . J'ai essayé de réduire cela à "si result = 0 alors garder à 0, sinon mettez le à 1" . Cela fonctionne généralement, mais je finis par avoir:
day | name | type | case | count
------------+----------------+------+------+-------
2013-11-06 | modelA | 1 | 0 | 972
2013-11-06 | modelA | 1 | 1 | 42
2013-11-06 | modelA | 1 | 1 | 2
2013-11-06 | modelA | 1 | 1 | 11
2013-11-06 | modelB | 1 | 0 | 456
2013-11-06 | modelB | 1 | 1 | 16
2013-11-06 | modelB | 1 | 1 | 8
2013-11-06 | modelB | 3 | 0 | 21518
2013-11-06 | modelB | 3 | 1 | 5
2013-11-06 | modelB | 3 | 1 | 7
2013-11-06 | modelB | 3 | 1 | 563
Au lieu de l'agrégat que j'essaie d'atteindre, il ne contient qu'une ligne par combinaison type/cas.
day | name | type | case | count
------------+----------------+------+------+-------
2013-11-06 | modelA | 1 | 0 | 972
2013-11-06 | modelA | 1 | 1 | 55
2013-11-06 | modelB | 1 | 0 | 456
2013-11-06 | modelB | 1 | 1 | 24
2013-11-06 | modelB | 3 | 0 | 21518
2013-11-06 | modelB | 3 | 1 | 575
Voici ma requête:
select CURRENT_DATE-1 AS day, model.name, attempt.type,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END,
count(*)
from attempt attempt, prod_hw_id prod_hw_id, model model
where time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
group by model.name, attempt.type, attempt.result
order by model.name, attempt.type, attempt.result;
Tous les conseils sur la façon dont je peux atteindre ce serait génial.
Le jour sera toujours défini dans la clause WHERE
et ne variera donc pas. name, type, result(case)
et count
varieront. En bref, pour un modèle donné, je veux seulement 1 ligne par "type + cas" combo. Comme vous pouvez le voir dans le premier jeu de résultats, j'ai 3 lignes pour modelA
qui ont type=1
et case=1
(car il y a beaucoup de "résultat" valeurs que j'ai converties en 0 = 0 et rien d'autre = 1 ). Je veux que cela soit représenté comme une ligne avec le nombre agrégé comme dans l'exemple 2.
Votre requête fonctionnait déjà - sauf que vous rencontrez des conflits de noms ou que vous confondez la colonne de sortie (l'expression CASE
) avec la colonne source} _ result
, dont le contenu est différent.
...
GROUP BY model.name, attempt.type, attempt.result
...
Vous devez GROUP BY
votre expression CASE
à la place de votre colonne source:
...
GROUP BY model.name, attempt.type
, CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END
...
Vous pouvez également fournir un alias de colonne} différent de tout nom de colonne de la liste FROM
. 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. Citer le manuel ici:
Le nom d'une colonne de sortie peut être utilisé pour faire référence à la valeur de la colonne dans clauses
ORDER BY
etGROUP BY
, mais pas dans les clausesWHERE
ouHAVING
; là vous devez écrire l'expression à la place.
Et:
Si une expression
ORDER BY
est un nom simple qui correspond à la fois à une sortie nom de colonne et un nom de colonne en entrée,ORDER BY
l'interprétera comme le nom de la colonne de sortie. _ {C'est l'inverse du choix queGROUP BY
.__ fera.} Dans la même situation. Cette incohérence est faite pour être compatible avec le standard SQL.
Gras l'emphase est la mienne.
Ces conflits peuvent être évités en utilisant références de position (nombres ordinaux) dans GROUP BY
et ORDER BY
, en référençant les éléments de la liste SELECT
de gauche à droite. Voir la solution ci-dessous.
L’inconvénient est que ceci peut être plus difficile à lire et vulnérable aux modifications de la liste SELECT
(on pourrait oublier d’adapter les références de position en conséquence).
Mais vous pas devez ajouter la colonne day
à la clause GROUP BY
tant qu'elle contient une valeur constante (CURRENT_DATE-1
).
Réécrit et simplifié avec la syntaxe JOIN et les références de position appropriées, 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. En outre, votre "temps" est évidemment un timestamp
OU date
, ce qui est plutôt trompeur.
pouvez-vous s'il vous plaît essayer ceci: remplacer la déclaration de cas par celle ci-dessous
Sum(CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END) as Count,
Essayez d’ajouter les deux autres colonnes non COUNT à GROUP BY:
select CURRENT_DATE-1 AS day,
model.name,
attempt.type,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END,
count(*)
from attempt attempt, prod_hw_id prod_hw_id, model model
where time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
group by 1,2,3,4
order by model.name, attempt.type, attempt.result;
Pour TSQL, j'aime bien encapsuler des instructions case dans une application externe. Cela évite d'avoir à écrire l'instruction case deux fois, permet de faire référence à l'instruction case par alias lors de futures jointures et évite le recours à des références de position.
select oa.day,
model.name,
attempt.type,
oa.result
COUNT(*) MyCount
FROM attempt attempt, prod_hw_id prod_hw_id, model model
WHERE time >= '2013-11-06 00:00:00'
AND time < '2013-11-07 00:00:00'
AND attempt.hard_id = prod_hw_id.hard_id
AND prod_hw_id.model_id = model.model_id
OUTER APPLY (
SELECT CURRENT_DATE-1 AS day,
CASE WHEN attempt.result = 0 THEN 0 ELSE 1 END result
) oa
group by oa.day,
model.name,
attempt.type,
oa.result
order by model.name, attempt.type, oa.result;