Générer un histogramme à partir des valeurs de colonne d'une base de données
-
20-08-2019 - |
Question
Disons que j'ai une colonne de "base de données" comme celle-ci:
|grade|
| 1|
| 2|
| 1|
| 3|
| 4|
| 5|
Existe-t-il une méthode non-triviale en SQL pour générer un histogramme comme celui-ci?
|2,1,1,1,1,0|
où 2 signifie que la note 1 a lieu deux fois, les notes moyennes de 1 s {2..5} se produisent une fois et 0 signifie que la note 6 ne se produit pas du tout.
Cela ne me dérange pas si l'histogramme est une ligne par compte.
Si cela compte, la base de données est SQL Server accessible par un CGI perl via unixODBC / FreeTDS.
MODIFIER: Merci pour vos réponses rapides! Cela ne pose pas de problème si des valeurs inexistantes (comme la 6e année dans l'exemple ci-dessus) ne se produisent pas tant que je peux déterminer quelle valeur d'histogramme appartient à quelle année.
La solution
SELECT COUNT(grade) FROM table GROUP BY grade ORDER BY grade
Je ne l’ai pas vérifié, mais cela devrait fonctionner. Il ne sera cependant pas pris en compte pour la note 6s, car il n’est pas du tout présent dans le tableau ...
Autres conseils
Utilisez une table temporaire pour obtenir vos valeurs manquantes:
CREATE TABLE #tmp(num int)
DECLARE @num int
SET @num = 0
WHILE @num < 10
BEGIN
INSERT #tmp @num
SET @num = @num + 1
END
SELECT t.num as [Grade], count(g.Grade) FROM gradeTable g
RIGHT JOIN #tmp t on g.Grade = t.num
GROUP by t.num
ORDER BY 1
S'il y a beaucoup de points de données, vous pouvez également group va ensemble comme ceci:
SELECT FLOOR(grade/5.00)*5 As Grade,
COUNT(*) AS [Grade Count]
FROM TableName
GROUP BY FLOOR(Grade/5.00)*5
ORDER BY 1
De plus, si vous souhaitez étiqueter toute la gamme, vous pouvez obtenir le plancher et le plafond à l’avance avec un CTE.
With GradeRanges As (
SELECT FLOOR(Score/5.00)*5 As GradeFloor,
FLOOR(Score/5.00)*5 + 4 As GradeCeiling
FROM TableName
)
SELECT GradeFloor,
CONCAT(GradeFloor, ' to ', GradeCeiling) AS GradeRange,
COUNT(*) AS [Grade Count]
FROM GradeRanges
GROUP BY GradeFloor, CONCAT(GradeFloor, ' to ', GradeCeiling)
ORDER BY GradeFloor
Remarque : dans certains moteurs SQL, vous pouvez GROUP BY
créer un index de colonne ordinale, mais avec MS SQL, si vous le souhaitez dans l'instruction SELECT
, vous devrez groupe également, copiant ainsi la plage dans l’expression de groupe.
Option 2 : vous pouvez utiliser les instructions case pour compter de manière sélective les valeurs dans des bacs arbitraires, puis les dé-balancer pour obtenir un nombre ligne par ligne des valeurs incluses
L’utilisation de DISTINCT par Gamecat me semble un peu étrange, je devrai l’essayer quand je serai de retour au bureau ...
La façon dont je le ferais est similaire mais ...
SELECT
[table].grade AS [grade],
COUNT(*) AS [occurances]
FROM
[table]
GROUP BY
[table].grade
ORDER BY
[table].grade
Pour pallier le manque de données où il n’ya pas d’occurrences 0, vous pouvez LEFT JOIN sur une table contenant toutes les notes valides. COUNT (*) comptera NULLS, mais COUNT (grade) ne comptera pas NULLS.
DECLARE @grades TABLE (
val INT
)
INSERT INTO @grades VALUES (1)
INSERT INTO @grades VALUES (2)
INSERT INTO @grades VALUES (3)
INSERT INTO @grades VALUES (4)
INSERT INTO @grades VALUES (5)
INSERT INTO @grades VALUES (6)
SELECT
[grades].val AS [grade],
COUNT([table].grade) AS [occurances]
FROM
@grades AS [grades]
LEFT JOIN
[table]
ON [table].grade = [grades].val
GROUP BY
[grades].val
ORDER BY
[grades].val
select Grade, count(Grade)
from MyTable
group by Grade
Selon l'article de Shlomo Priymak Comment Créez rapidement un histogramme dans MySQL , vous pouvez utiliser la requête suivante:
SELECT grade,
COUNT(\*) AS 'Count',
RPAD('', COUNT(\*), '*') AS 'Bar'
FROM grades
GROUP BY grade
Qui produira le tableau suivant:
grade Count Bar
1 2 **
2 1 *
3 1 *
4 1 *
5 1 *
Je me base sur ce que Ilya Volodin a fait ci-dessus, qui devrait vous permettre de sélectionner une plage de niveaux que vous souhaitez regrouper dans votre résultat:
DECLARE @cnt INT = 0;
WHILE @cnt < 100 -- Set max value
BEGIN
SELECT @cnt,COUNT(fe) FROM dbo.GEODATA_CB where fe >= @cnt-0.999 and fe <= @cnt+0.999 -- set tolerance
SET @cnt = @cnt + 1; -- set step
END;