假设我有一个带有数字列的表(我们称之为“得分”)。
我想生成一个计数表,显示每个范围内出现的分数。
例如:
score range | number of occurrences ------------------------------------- 0-9 | 11 10-19 | 14 20-29 | 3 ... | ...
在这个例子中有11行,得分在0到9之间,14行得分在10到19之间,3行得分在20-29之间。
有没有简单的方法来设置它?你推荐什么?
答案 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引擎都有规则!