我需要选择属于这个范围的项目数
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;
显然,如果范围内没有项目,则不会包含在输出中。我可以想到一些不太优雅的方法来包含输出中的所有范围,但是有一个优雅而快速的方法(在PostgreSQL或MS SQL Server方言中)
答案 0 :(得分: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;
我使用了width_bucket
而不是简单的除法和模数,因为它更通用,更容易适应更复杂的范围。而且,它太棒了。
Mark Bannister用于序列生成的递归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;
如果您希望/10
超过width_bucket
(例如,如果MS SQL中没有width_bucket
),那么很容易更改回来。
输出:
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)
答案 1 :(得分:4)
Postgresql 9.2还实现了范围类型:
SELECT
range.r,
count(val.n)
FROM
(VALUES (int4range '[0, 10)'), (int4range '[10, 20)'), (int4range '[20, 30)'), (int4range '[30, 40)')) range (r)
LEFT JOIN (VALUES (2), (3), (9), (11), (17), (31), (33)) AS val (n) ON val.n <@ range.r
GROUP BY
range.r
ORDER BY r ASC
┌─────────┬───────┐
│ r │ count │
├─────────┼───────┤
│ [0,10) │ 3 │
│ [10,20) │ 2 │
│ [20,30) │ 0 │
│ [30,40) │ 2 │
└─────────┴───────┘
答案 2 :(得分:3)
尝试:
with ranges as
(select 0 rangev union all
select rangev+1 as rangev
from ranges
where rangev < 4)
select count(val) as qty , rangev
from ranges
left join numbers on rangev = val / 10
group by rangev;
(对于PostgresQL,SQLServer版本 - 将with ranges
更改为with recursive ranges
)
答案 3 :(得分:1)
对于MS SQL Server
declare @min int, @max int
select @min = MIN(val/10), @max = MAX(val/10) from numbers
select ranges.number as range, COUNT(val) as qty from master.dbo.spt_values ranges
left join numbers on ranges.number = numbers.val/10
where type='p' and number between @min and @max
group by number
同样的原则可以适用于Postgres,尽管数字列表的生成会有所不同