什么是SQL频率分布查询,用于按组计数范围,并包括0计数?

9

给定:

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计数的范围?我发现类似于计算范围的stackoverflow问题,其中一些涉及到0计数,但它们需要指定每个范围(要么将范围硬编码进查询中,要么将范围放入表格中)。我更喜欢使用像上面那样的通用查询,无需显式指定每个范围(例如,0-10,10-20,20-30,...)。 我正在使用PostgreSQL 9.1.3。是否有一种方法可以修改上述简单的查询以包含0计数?类似:
Oracle:如何“按范围”分组?
在MySQL中获取十进制范围的频率分布
2个回答

14
< p > 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(包括0和10)的值。

如果需要,您可以将两个查询(一个用于确定范围,一个用于计算计数)封装成一个函数。


很好。这是一个不错的函数值得了解。 - Glenn
优雅的回答,@mu_is_too_short!我尝试了一下,它起作用了。正是我在寻找的。谢谢! - Rob Bednark
@Glenn:是的,generate_series非常有用,它还可以与时间戳一起使用,所以再见了日历表。 - mu is too short

3
您需要一种方法来创建年龄范围的表格。通常使用行号。对大表进行笛卡尔积,即可获得许多数字。
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;

编辑:mu is too short给出了更为优雅的答案,但是如果你的数据库上没有generate_series函数...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接