227 votes

En SQL, comment peut-on "grouper par" dans des plages ?

Supposons que j'ai un tableau avec une colonne numérique (appelons-la "score").

J'aimerais générer un tableau de comptes, qui montre combien de fois les scores sont apparus dans chaque plage.

Par exemple :

score range  | number of occurrences
-------------------------------------
   0-9       |        11
  10-19      |        14
  20-29      |         3
   ...       |       ...

Dans cet exemple, il y avait 11 lignes avec des notes comprises entre 0 et 9, 14 lignes avec des notes comprises entre 10 et 19, et 3 lignes avec des notes comprises entre 20 et 29.

Existe-t-il un moyen simple de mettre en place ce système ? Que recommandez-vous ?

179voto

Ron Tuffin Points 8286

Aucune des réponses les plus votées n'est correcte sur SQL Server 2000. Peut-être utilisaient-ils une version différente.

Voici les versions correctes de ces deux éléments sur SQL Server 2000.

select t.range as [score range], count(*) as [number of occurences]
from (
  select case  
    when score between 0 and 9 then ' 0- 9'
    when score between 10 and 19 then '10-19'
    else '20-99' end as range
  from scores) t
group by t.range

ou

select t.range as [score range], count(*) as [number of occurrences]
from (
      select user_id,
         case when score >= 0 and score< 10 then '0-9'
         when score >= 10 and score< 20 then '10-19'
         else '20-99' end as range
     from scores) t
group by t.range

0 votes

Puis-je également agréger une autre colonne (comme le nombre de groupes) ? Par exemple, je veux agréger la colonne des bourses d'études pour chaque gamme de résultats. J'ai essayé, mais je n'y arrive pas

0 votes

Bonne réponse @Ron Tuffin, cependant lorsque vous avez deux plages comme 10-20 , 100-200, alors l'ordre ne fonctionne pas. Vous auriez un ordre comme 10-20, 100-200, 20-30 etc. Une astuce pour l'ordre par ?

2 votes

@ZoHas c'est un peu un hack mais cela fonctionne : order by len(t.range),t.range

45voto

Walter Mitty Points 8726

Une autre approche consisterait à stocker les plages dans une table, au lieu de les intégrer à la requête. Vous obtiendriez une table, appelée Ranges, qui ressemblerait à ceci :

LowerLimit   UpperLimit   Range 
0              9          '0-9'
10            19          '10-19'
20            29          '20-29'
30            39          '30-39'

Et une requête qui ressemble à ça :

Select
   Range as [Score Range],
   Count(*) as [Number of Occurences]
from
   Ranges r inner join Scores s on s.Score between r.LowerLimit and r.UpperLimit
group by Range

Cela implique la création d'un tableau, mais il serait facile de le maintenir lorsque les plages souhaitées changent. Aucun changement de code n'est nécessaire !

0 votes

J'ai posé une question sur les administrateurs de bases de données Conception de tableaux pour les données structurées utilisant des gammes de godets variables qui n'a pas eu de réponse, mais j'ai fini par concevoir un système qui a les gammes que vous avez mentionnées. J'adore cette réponse.

33voto

Ken Paul Points 2398

Je vois ici des réponses qui ne fonctionneront pas avec la syntaxe de SQL Server. Je les utiliserais :

select t.range as [score range], count(*) as [number of occurences]
from (
  select case 
    when score between  0 and  9 then ' 0-9 '
    when score between 10 and 19 then '10-19'
    when score between 20 and 29 then '20-29'
    ...
    else '90-99' end as range
  from scores) t
group by t.range

EDIT : voir les commentaires

0 votes

C'est peut-être dû à la version de SQLServer que j'utilise, mais pour que votre exemple fonctionne (je teste les choses avant de les voter), j'ai dû déplacer le "score" de la fin du "cas" à la fin de chaque "quand".

3 votes

Vous avez raison, et merci pour la correction. Apparemment, lorsque vous placez la variable après le mot clé "case", vous ne pouvez effectuer que des correspondances exactes, et non des expressions. J'apprends autant en répondant aux questions qu'en les posant :-)

31voto

mhawke Points 10385

Dans postgres (où || est l'opérateur de concaténation de chaînes de caractères) :

select (score/10)*10 || '-' || (score/10)*10+9 as scorerange, count(*)
from scores
group by score/10
order by 1

donne :

 scorerange | count 
------------+-------
 0-9        |    11
 10-19      |    14
 20-29      |     3
 30-39      |     2

13voto

Timothy Walters Points 8222

La réponse de James Curran était la plus concise à mon avis, mais le résultat n'était pas correct. Pour SQL Server, la déclaration la plus simple est la suivante :

SELECT 
    [score range] = CAST((Score/10)*10 AS VARCHAR) + ' - ' + CAST((Score/10)*10+9 AS VARCHAR), 
    [number of occurrences] = COUNT(*)
FROM #Scores
GROUP BY Score/10
ORDER BY Score/10

Ceci suppose une table temporaire #Scores que j'ai utilisée pour le tester, j'ai juste rempli 100 lignes avec des nombres aléatoires entre 0 et 99.

1 votes

Ah... Il y a l'avantage de prendre le temps de créer le tableau. (J'ai utilisé un tableau existant avec trop peu de lignes sur une plage trop petite).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X