在SQL中,如何在范围内“分组”?

时间:2008-10-24 03:26:27

标签: sql sql-server tsql

假设我有一个带有数字列的表(我们称之为“得分”)。

我想生成一个计数表,显示每个范围内出现的分数。

例如:

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

在这个例子中有11行,得分在0到9之间,14行得分在10到19之间,3行得分在20-29之间。

有没有简单的方法来设置它?你推荐什么?

16 个答案:

答案 0 :(得分:128)

SQLServer 2000上的最高投票答案都不正确。也许他们使用的是其他版本。

以下是SQLServer 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

select t.range as [score range], count(*) as [number of occurences]
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

答案 1 :(得分:32)

另一种方法是将范围存储在表中,而不是将它们嵌入查询中。你最终得到一张桌子,称之为Ranges,看起来像这样:

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

一个看起来像这样的查询:

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

这意味着设置一个表,但是当所需的范围发生变化时,它很容易维护。无需更改代码!

答案 2 :(得分:30)

我在这里看到的答案在SQL Server语法中不起作用。我会用:

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

编辑:见评论

答案 3 :(得分:20)

在postgres中(其中||是字符串连接运算符):

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

给出:

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

答案 4 :(得分:10)

James Curran的回答在我看来最简洁,但输出不正确。对于SQL Server,最简单的语句如下:

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

这假设我用来测试它的#Scores临时表,我只用0到99之间的随机数填充了100行。

答案 5 :(得分:5)

create table scores (
   user_id int,
   score int
)

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

答案 6 :(得分:5)

select cast(score/10 as varchar) + '-' + cast(score/10+9 as varchar), 
       count(*)
from scores
group by score/10

答案 7 :(得分:4)

这将允许您不必指定范围,并且应该是SQL Server不可知的。数学FTW!

SELECT CONCAT(range,'-',range+9), COUNT(range)
FROM (
  SELECT 
    score - (score % 10) as range
  FROM scores
)

答案 8 :(得分:3)

我会以不同的方式做到这一点,以便在不必定义每个案例的情况下进行扩展:

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

未经测试,但您明白了......

答案 9 :(得分:2)

declare @RangeWidth int

set @RangeWidth = 10

select
   Floor(Score/@RangeWidth) as LowerBound,
   Floor(Score/@RangeWidth)+@RangeWidth as UpperBound,
   Count(*)
From
   ScoreTable
group by
   Floor(Score/@RangeWidth)

答案 10 :(得分:1)

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

如果您使用的是MySQL,请确保使用“范围”以外的单词,否则运行上述示例时会出现错误。

答案 11 :(得分:1)

因为在(Range)上排序的列是一个字符串,所以使用字符串/单词排序而不是数字排序。

只要字符串有零填充数字长度,排序仍应在语义上正确:

SELECT t.range AS ScoreRange,
       COUNT(*) AS NumberOfOccurrences
  FROM (SELECT CASE
                    WHEN score BETWEEN 0 AND 9 THEN '00-09'
                    WHEN score BETWEEN 10 AND 19 THEN '10-19'
                    ELSE '20-99'
               END AS Range
          FROM Scores) t
 GROUP BY t.Range

如果范围混合,只需填充额外的零:

SELECT t.range AS ScoreRange,
       COUNT(*) AS NumberOfOccurrences
  FROM (SELECT CASE
                    WHEN score BETWEEN 0 AND 9 THEN '000-009'
                    WHEN score BETWEEN 10 AND 19 THEN '010-019'
                    WHEN score BETWEEN 20 AND 99 THEN '020-099'
                    ELSE '100-999'
               END AS Range
          FROM Scores) t
 GROUP BY t.Range

答案 12 :(得分:1)

尝试

SELECT (str(range) + "-" + str(range + 9) ) AS [Score range], COUNT(score) AS [number of occurances]
FROM (SELECT  score,  int(score / 10 ) * 10  AS range  FROM scoredata )  
GROUP BY range;

答案 13 :(得分:0)

select t.range as score, count(*) as Count 
from (
      select UserId,
         case when isnull(score ,0) >= 0 and isnull(score ,0)< 5 then '0-5'
                when isnull(score ,0) >= 5 and isnull(score ,0)< 10 then '5-10'
                when isnull(score ,0) >= 10 and isnull(score ,0)< 15 then '10-15'
                when isnull(score ,0) >= 15 and isnull(score ,0)< 20 then '15-20'               
         else ' 20+' end as range
         ,case when isnull(score ,0) >= 0 and isnull(score ,0)< 5 then 1
                when isnull(score ,0) >= 5 and isnull(score ,0)< 10 then 2
                when isnull(score ,0) >= 10 and isnull(score ,0)< 15 then 3
                when isnull(score ,0) >= 15 and isnull(score ,0)< 20 then 4             
         else 5  end as pd
     from score table
     ) t

group by t.range,pd order by pd

答案 14 :(得分:0)

我来这里是因为我有类似的问题,但我发现简短的答案是错误的,并且带有连续“case when”的答案需要大量工作,并且在我的代码中看到任何重复的内容都会伤害我的眼睛。所以这是解决方案

SELECT --MIN(score), MAX(score),
    [score range] = CAST(ROUND(score-5,-1)AS VARCHAR) + ' - ' + CAST((ROUND(score-5,-1)+10)AS VARCHAR),
    [number of occurrences] = COUNT(*)
FROM order
GROUP BY  CAST(ROUND(score-5,-1)AS VARCHAR) + ' - ' + CAST((ROUND(score-5,-1)+10)AS VARCHAR)
ORDER BY MIN(score)


答案 15 :(得分:-1)

也许你问的是要保持这样的事情......

当然,您将为查询调用全表扫描,如果包含需要计算的分数(聚合)的表很大,您可能需要更好的解决方案,您可以创建辅助表并使用规则,例如on insert - 你可能会调查它。

但并非所有RDBMS引擎都有规则!