SQL에서 범위를 어떻게 "그룹화"할 수 있습니까?


181

숫자 열이있는 테이블이 있다고 가정합니다 ( "스코어"라고 함).

카운트 테이블을 생성하고 싶습니다. 각 테이블에 점수가 몇 번이나 나타 났는지 보여줍니다.

예를 들면 다음과 같습니다.

점수 범위 | 발생 횟수
-------------------------------------
   0-9 | 11
  10-19 | 14
  20-29 | 삼
   ... | ...

이 예에서는 0 ~ 9 범위의 점수를 가진 11 개의 행, 10 ~ 19 범위의 점수를 가진 14 개의 행과 20-29 범위의 점수를 가진 3 개의 행이있었습니다.

이것을 설정하는 쉬운 방법이 있습니까? 추천 메뉴가 무엇인가요?

답변:


143

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

그룹 수와 같은 다른 열도 집계 할 수 있습니까? 각 점수 범위에 대한 장학금 열을 집계하고 싶다고 가정합니다. 나는 노력했지만, 제대로 이해하지
못함

@Ron Tuffin의 좋은 대답이지만 10-20, 100-200과 같은 두 가지 범위가 있으면 순서가 작동하지 않습니다. 당신은 10-20, 100-200,20-30 등등과 같이 주문할 것입니다.
Zo

2
@ZoHas 그것은 약간의 해킹이지만 작동합니다 : len (t.range), t.range로 주문
Ron Tuffin


1
여전히 구문 문제가있는 경우 다음 답변을 확인하십시오. dba.stackexchange.com/questions/22491/…
Robert Hosking

33

다른 방법은 범위를 쿼리에 포함시키는 대신 테이블에 저장하는 것입니다. 테이블로 끝나고 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

이것은 테이블을 설정하는 것을 의미하지만 원하는 범위가 변경되면 유지 관리가 쉽습니다. 코드를 변경할 필요가 없습니다!


나는 대답 을 얻지 못한 가변 버킷 범위사용하는 패턴 화 된 데이터를위한 데이터베이스 관리자 테이블 디자인에 대한 질문을했지만 결국 언급 한 범위를 가진 시스템을 설계하게되었습니다. 이 답변을 좋아하십시오.
ΩmegaMan

31

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

편집 : 의견보기


아마도 사용중인 SQLServer 버전 때문일 수 있지만 예제를 작동시키기 위해 (투표하기 전에 테스트) 나는 'case'이후에서 각 'when'뒤로 'score'를 이동해야했습니다.
Ron Tuffin

3
네 말이 맞아, 정정 해줘서 고마워 분명히 키워드 'case'뒤에 변수를 넣으면 표현식이 아닌 정확히 일치하는 항목 만 수행 할 수 있습니다. 나는 질문을하는 것보다 질문에 대한 답변을 통해 많은 것을 배웁니다. :-)
Ken Paul

23

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

11

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 개의 행을 채웠습니다.


1
아 ... 실제로 테이블을 만드는 데 시간이 걸리는 장점이 있습니다. (나도 몇 행에 걸쳐 너무 작은 범위가 기존 테이블을 사용)
제임스 쿠란

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

감사! 나는 이것을 시도했지만 기본 아이디어는 훌륭하게 작동하지만 사용해야하는 구문은 약간 다릅니다. 첫 번째 "case"키워드 만 필요하다가 마지막 조건 후에 "as as range"전에 "end"키워드가 필요합니다. 그 외에는 크게 감사했습니다!
Hugh

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

나는 이것을 좋아하지만 쿼리를 표시하려면 쿼리 외부의 범위를 수정해야합니다.
tvanfosson

답변을 수정하기로 결정한 경우 첫 번째 줄에서 점수 10을 (점수 / 10) * 10으로 변경해야합니다. 그렇지 않으면 30-39 대신 3-12가됩니다. 아래에서 주문을 추가하여 올바른 순서로 결과를 얻을 수 있습니다.
Timothy Walters

5

이를 통해 범위를 지정할 필요가 없으며 SQL 서버에 구애받지 않아야합니다. 수학 FTW!

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

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

테스트되지는 않았지만 아이디어가 있습니다 ...


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)

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을 사용하는 경우 'range'이외의 단어를 사용하십시오. 그렇지 않으면 위 예제를 실행하면 오류가 발생합니다.


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

범위가 혼합되면 추가로 0을 채 웁니다.

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

시험

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;

3
쿼리로 문제를 해결하는 방법에 대한 설명을 추가 할 수 있으면 도움이됩니다.
devlin carnate

-1

아마도 당신은 그런 일을 계속하는 것에 대해 묻고있을 것입니다 ...

물론 쿼리에 대한 전체 테이블 스캔을 호출하고 계산해야하는 점수 (집계)가 포함 된 테이블이 큰 경우 더 나은 성능의 솔루션을 원할 경우 보조 테이블을 작성하고 다음과 같은 규칙을 사용할 수 있습니다. on insert-당신은 그것을 볼 수 있습니다.

그러나 모든 RDBMS 엔진에 규칙이있는 것은 아닙니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.