SQL frequency distribution query to count ranges with group-by and include 0 counts

浪尽此生 提交于 2019-12-03 00:08:13

generate_series to the rescue:

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

Figuring out the upper bound for generate_series should be trivial with a separate query, I just used 10 as a placeholder.

This:

generate_series(0, 10) s(d)

essentially generates an inline table called s with a single column d which contains the values from 0 to 10 (inclusive).

You could wrap the two queries (one to figure out the range, one to compute the counts) into a function if necessary.

You need some way to invent the table of age ranges. Row number usually works nicely. Do a cartesian product against a big table to get lots of numbers.

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;

EDIT: mu is too short has a much more elegant answer, but if you didn't have a generate_series function on the db, ... :)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!