In SQL, how can you “group by” in ranges?

前端 未结 15 2187
粉色の甜心
粉色の甜心 2020-11-22 15:38

Suppose I have a table with a numeric column (lets call it \"score\").

I\'d like to generate a table of counts, that shows how many times scores appeared in each ran

相关标签:
15条回答
  • 2020-11-22 16:30

    This will allow you to not have to specify ranges, and should be SQL server agnostic. Math FTW!

    SELECT CONCAT(range,'-',range+9), COUNT(range)
    FROM (
      SELECT 
        score - (score % 10) as range
      FROM scores
    )
    
    0 讨论(0)
  • 2020-11-22 16:30
    select t.blah 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 blah
      from scores) t
    group by t.blah
    

    Make sure you use a word other than 'range' if you are in MySQL, or you will get an error for running the above example.

    0 讨论(0)
  • 2020-11-22 16:31

    An alternative approach would involve storing the ranges in a table, instead of embedding them in the query. You would end up with a table, call it Ranges, that looks like this:

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

    And a query that looks like this:

    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
    

    This does mean setting up a table, but it would be easy to maintain when the desired ranges change. No code changes necessary!

    0 讨论(0)
  • 2020-11-22 16:34

    James Curran's answer was the most concise in my opinion, but the output wasn't correct. For SQL Server the simplest statement is as follows:

    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
    

    This assumes a #Scores temporary table I used to test it, I just populated 100 rows with random number between 0 and 99.

    0 讨论(0)
  • 2020-11-22 16:35

    I would do this a little differently so that it scales without having to define every case:

    select t.range as [score range], count(*) as [number of occurences]
    from (
      select FLOOR(score/10) as range
      from scores) t
    group by t.range
    

    Not tested, but you get the idea...

    0 讨论(0)
  • 2020-11-22 16:36

    In postgres (where || is the string concatenation operator):

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

    gives:

     scorerange | count 
    ------------+-------
     0-9        |    11
     10-19      |    14
     20-29      |     3
     30-39      |     2
    
    0 讨论(0)
提交回复
热议问题