В SQL, как вы можете "группировать себя" в диапазонах?

Предположим, что у меня есть таблица с числовым столбцом (давайте назовем ее "оценка" ).

Я бы хотел создать таблицу подсчетов, которая показывает, сколько раз в каждом диапазоне появлялись баллы.

Например:

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

В этом примере было 11 строк с оценками в диапазоне от 0 до 9, 14 строк с оценками в диапазоне от 10 до 19 и 3 строки с оценками в диапазоне 20-29.

Есть ли простой способ установить это? Что вы рекомендуете?

Ответ 1

Ни один из самых высоких голосовых ответов не является правильным на 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

Ответ 2

Здесь я вижу ответы, которые не будут работать в синтаксисе 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

Альтернативный подход предполагает хранение диапазонов в таблице вместо их внедрения в запрос. В итоге вы получите таблицу, назовите ее "Диапазоны", которая выглядит так:

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

Это означает настройку таблицы, но ее можно будет легко сохранить при изменении требуемых диапазонов. Никаких изменений кода не требуется!

Ответ 4

В 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

Ответ 5

Ответ Джеймса Каррана был самым кратким, на мой взгляд, но результат был неправильным. Для 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, которую я использовал для ее проверки, я просто заполнил 100 строк со случайным числом от 0 до 99.

Ответ 6

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

Ответ 7

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

Ответ 8

Это позволит вам не указывать диапазоны и быть агностиком SQL-сервера. Математика FTW!

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

Ответ 9

Я бы сделал это несколько иначе, чтобы он масштабировался без необходимости определять каждый случай:

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

Не тестировалось, но вы поняли...

Ответ 10

declare @RangeWidth int

set @RangeWidth = 10

select
   Floor(Score/@RangeWidth) as LowerBound,
   Floor(Score/@RangeWidth)[email protected] as UpperBound,
   Count(*)
From
   ScoreTable
group by
   Floor(Score/@RangeWidth)

Ответ 11

Поскольку сортируемый столбец (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

Try

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

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

Убедитесь, что вы используете слово, отличное от "range", если вы находитесь в MySQL, или вы получите сообщение об ошибке для выполнения приведенного выше примера.

Ответ 14

Возможно, вы просите о том, чтобы такие вещи шли...

Конечно, вы вызовете полное сканирование таблицы для запросов, и если таблица, содержащая оценки, которые должны быть подсчитаны (скопления), велика, вам может понадобиться более эффективное решение, вы можете создать вторичную таблицу и использовать правила, например on insert - вы можете изучить его.

Однако у всех двигателей РСУБД есть правила!