web-dev-qa-db-ja.com

SQLでは、どのようにして範囲を「グループ化」できますか?

数値列のあるテーブルがあるとします(「スコア」と呼びます)。

カウントのテーブルを生成します。これは、各範囲にスコアが何回出現したかを示します。

例えば:

スコア範囲|発生回数
 ------------------------------------- 
 0-9 | 11 
 10-19 | 14 
 20-29 | 3 
 ... | ... 

この例では、0〜9の範囲のスコアを持つ11行と、10〜19の範囲のスコアを持つ14行と、20〜29の範囲のスコアを持つ3行がありました。

これを設定する簡単な方法はありますか?何がお勧めですか?

168
Hugh

最も投票数の多い回答はどちらも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
132
Ron Tuffin

別のアプローチでは、クエリに範囲を埋め込む代わりに、テーブルに範囲を格納します。次のようなテーブルが作成され、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

これは、テーブルを設定することを意味しますが、目的の範囲が変わったときに簡単に維持できます。コードを変更する必要はありません!

32
Walter Mitty

ここには、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

編集:コメントを見る

30
Ken Paul

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
21
mhawke

ジェームス・カランの答えは私の意見では最も簡潔でしたが、出力は正しくありませんでした。 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行を挿入しました。

10
Timothy Walters
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
5
tvanfosson
select cast(score/10 as varchar) + '-' + cast(score/10+9 as varchar), 
       count(*)
from scores
group by score/10
5
James Curran

これにより、範囲を指定する必要がなくなり、SQLサーバーに依存しなくなります。数学FTW!

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

すべてのケースを定義する必要なくスケーリングできるように、これを少し異なる方法で行います。

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

テストされていないが、あなたはアイデアを得る...

3
JoshNaro
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)
2
Aheho

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
1
Kevin Hogg

試して

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;
1
Stubo
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を使用している場合は、「範囲」以外のWordを使用するようにしてください。使用しない場合、上記の例を実行するとエラーが発生します。

1
Danny Hui