Запрос распределения частот SQL для подсчета диапазонов с группированием и включения 0 отсчетов - PullRequest
9 голосов
/ 13 марта 2012

Учитывая:

table 'thing':

age
---
3.4
3.4
10.1
40
45
49

Я хочу посчитать количество вещей для каждого 10-летнего диапазона, например,

age_range | count
----------+-------
        0 |     2
        10|     1
        20|     0
        30|     0
        40|     3

Этот запрос близок:

SELECT FLOOR(age / 10) as age_range, COUNT(*)
FROM thing
GROUP BY FLOOR(age / 10) ORDER BY FLOOR(age / 10);

Вывод:

 age_range | count 
-----------+-------
         0 |     1
         1 |     2
         4 |     3

Тем не менее, он не показывает мне диапазоны, которые имеют 0 отсчетов.Как я могу изменить запрос таким образом, чтобы он также отображал диапазоны между 0 счетами?

Я нашел похожие вопросы о стековом потоке для подсчета диапазонов, некоторые для 0 счетчиков, но они связаны с необходимостью указать каждый диапазон (либо жесткий-кодирование диапазонов в запросе или помещение диапазонов в таблицу).Я бы предпочел использовать общий запрос, подобный приведенному выше, где мне не нужно явно указывать каждый диапазон (например, 0-10, 10-20, 20-30, ...).Я использую PostgreSQL 9.1.3.

Есть ли способ изменить приведенный выше простой запрос, включив в него 0 счетчиков?

Подобные:
Oracle: как "группировать"по диапазону?
Получить распределение частоты десятичного диапазона в MySQL

Ответы [ 2 ]

11 голосов
/ 13 марта 2012

generate_series на помощь:

select 10 * s.d, count(t.age)
from generate_series(0, 10) s(d)
left outer join thing t on s.d = floor(t.age / 10)
group by s.d
order by s.d

Определение верхней границы для generate_series должно быть тривиальным с отдельным запросом, я просто использовал 10 в качестве заполнителя.

Это:

generate_series(0, 10) s(d)

по существу генерирует встроенную таблицу с именем s с одним столбцом d, который содержит значения от 0 до 10 (включительно).

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

1 голос
/ 13 марта 2012

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

WITH RANGES AS (
SELECT (rownum - 1) * 10 AS age_range
  FROM ( SELECT row_number() OVER() as rownum
           FROM pg_tables
       ) n
      ,( SELECT ceil( max(age) / 10 )  range_end
           FROM thing
       ) m
  WHERE  n. rownum <= range_end
)
SELECT r.age_range, COUNT(t.age) AS count
  FROM ranges r
  LEFT JOIN thing t ON r.age_range = FLOOR(t.age / 10) * 10
  GROUP BY r.age_range
  ORDER BY r.age_range;

РЕДАКТИРОВАТЬ: мю слишком коротко, у него гораздо более элегантный ответ, но если у вас не было функции generate_series на БД,...:)

...