按范围分组记录

syn*_*pse 2 sql sql-server postgresql

我需要选择落在某个范围内的项目数

create table numbers (val int);

insert into numbers(val) values (2), (3), (11), (12), (13), (31);

select count(1) as qty , val / 10 as range
from numbers
group by val / 10;
Run Code Online (Sandbox Code Playgroud)

显然,如果范围内没有项目,它将不会包含在输出中.我可以想到一些不太优雅的方法来包含输出中的所有范围,但是有一个优雅而快速的方法(在PostgreSQL或MS SQL Server方言中)

Cra*_*ger 5

您似乎想要创建结果的直方图.

PostgreSQL的:

select x, count(val)
from generate_series(1,6) x 
left outer join numbers on (x = width_bucket(val, 0, 60, 6))
group by x;
Run Code Online (Sandbox Code Playgroud)

我使用的width_bucket不是简单的除法和模数,因为它更通用,更容易适应更复杂的范围.它也很棒.

Mark Ba​​nnister用于序列生成的递归CTE可以集成和连接,x而不是generate_series为了增加可移植性(如果需要),并且可以自动确定限制:

with recursive ranges(rangev) as (
    select 0 rangev union all select rangev+1 as rangev from ranges where rangev < 4
), bounds(lower_bucket, upper_bucket) as (
    select (min(val))/10, (max(val)/10)+1 from numbers
)
select
    rangev as bucket,
    rangev*10 AS lower_bound,
    (rangev+1)*10-1 AS upper_bound,
    count(val) AS num_in_bucket
from ranges cross join bounds
left outer join numbers on (rangev = width_bucket(val, lower_bucket, upper_bucket*10, upper_bucket))
group by rangev
order by rangev asc;
Run Code Online (Sandbox Code Playgroud)

如果你喜欢/10width_bucket(比方说,如果width_bucket不是在MS SQL可用),很容易改回来.

输出:

 bucket | lower_bound | upper_bound | num_in_bucket 
--------+-------------+-------------+---------------
      0 |           0 |           9 |             0
      1 |          10 |          19 |             2
      2 |          20 |          29 |             3
      3 |          30 |          39 |             0
      4 |          40 |          49 |             1
(5 rows)
Run Code Online (Sandbox Code Playgroud)