Postgres 按范围分组
Postgres grouping by range
我有这样的数据
我想要实现的是直方图的数据,它将值计入特定范围。对于 A 类值范围 1-100 和 B 类值范围 0-125,其中 C 类值 = 5。我遇到的问题是多行数据,我需要先在 C 上过滤,然后将值计入要显示的范围直方图。
要获得计数,可以说每 10 秒看起来像这样
生成数据的代码:
CREATE TEMP TABLE sample (
ts timestamp
,category varchar(2)
, val int)
insert into sample values
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'A', 12),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'A', 44),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'C', 1),
(to_timestamp('01.01.2018 08:00:04', 'dd-mm-yyyy hh24:mi:ss'), 'B', 24),
(to_timestamp('01.01.2018 08:00:05', 'dd-mm-yyyy hh24:mi:ss'), 'B', 111),
(to_timestamp('01.01.2018 08:00:06', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:07', 'dd-mm-yyyy hh24:mi:ss'), 'A', 145),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'B', 16),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'C', 47),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'B', 34),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'B', 111),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'A', 19),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'B', 46),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'C', 57)
我想如果我像这样旋转数据
s
elect
ts,
category,
case when category = 'A' then val end as "A",
case when category = 'B' then val end as "B",
case when category = 'C' then val end as "C"
from sample
order by ts
那么主元空值有问题
这里是:
with periods(pts) as
(
select *
from generate_series
(
timestamp '2018-01-01 08:00:00',
timestamp '2018-01-01 08:01:00',
interval '10 seconds'
) ts
)
select pts period_start,
pts + interval '10 seconds' period_end,
lat.cat_a,
lat.cat_b,
lat.cat_c
from periods
cross join lateral
(
select count(1) filter (where category = 'A' and val between 0 and 100) as cat_a,
count(1) filter (where category = 'B' and val between 0 and 125) as cat_b,
count(1) filter (where category = 'C' and val = 5) as cat_c
from sample
where ts >= pts and ts < pts + interval '10 seconds'
) lat;
period_start
period_end
cat_a
cat_b
cat_c
2018-01-01 08:00:00
2018-01-01 08:00:10
2
2
1
2018-01-01 08:00:10
2018-01-01 08:00:20
0
0
0
2018-01-01 08:00:20
2018-01-01 08:00:30
0
0
0
2018-01-01 08:00:30
2018-01-01 08:00:40
0
0
0
2018-01-01 08:00:40
2018-01-01 08:00:50
0
0
0
2018-01-01 08:00:50
2018-01-01 08:01:00
0
0
0
2018-01-01 08:01:00
2018-01-01 08:01:10
0
0
0
一排版很简单:
select min(ts) period_start,
max(ts) period_end,
count(1) filter (where category = 'A' and val between 0 and 100) as cat_a,
count(1) filter (where category = 'B' and val between 0 and 125) as cat_b,
count(1) filter (where category = 'C' and val = 5) as cat_c
from sample;
在澄清评论后添加
select * from (<the first version of the query here>) t where cat_c > 0;
我有这样的数据
我想要实现的是直方图的数据,它将值计入特定范围。对于 A 类值范围 1-100 和 B 类值范围 0-125,其中 C 类值 = 5。我遇到的问题是多行数据,我需要先在 C 上过滤,然后将值计入要显示的范围直方图。
要获得计数,可以说每 10 秒看起来像这样
生成数据的代码:
CREATE TEMP TABLE sample (
ts timestamp
,category varchar(2)
, val int)
insert into sample values
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'A', 12),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'A', 44),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'C', 1),
(to_timestamp('01.01.2018 08:00:04', 'dd-mm-yyyy hh24:mi:ss'), 'B', 24),
(to_timestamp('01.01.2018 08:00:05', 'dd-mm-yyyy hh24:mi:ss'), 'B', 111),
(to_timestamp('01.01.2018 08:00:06', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:07', 'dd-mm-yyyy hh24:mi:ss'), 'A', 145),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'B', 16),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'C', 47),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:02', 'dd-mm-yyyy hh24:mi:ss'), 'B', 34),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'B', 111),
(to_timestamp('01.01.2018 08:00:03', 'dd-mm-yyyy hh24:mi:ss'), 'C', 5),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'A', 19),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'B', 46),
(to_timestamp('01.01.2018 08:00:01', 'dd-mm-yyyy hh24:mi:ss'), 'C', 57)
我想如果我像这样旋转数据
s
elect
ts,
category,
case when category = 'A' then val end as "A",
case when category = 'B' then val end as "B",
case when category = 'C' then val end as "C"
from sample
order by ts
那么主元空值有问题
这里是:
with periods(pts) as
(
select *
from generate_series
(
timestamp '2018-01-01 08:00:00',
timestamp '2018-01-01 08:01:00',
interval '10 seconds'
) ts
)
select pts period_start,
pts + interval '10 seconds' period_end,
lat.cat_a,
lat.cat_b,
lat.cat_c
from periods
cross join lateral
(
select count(1) filter (where category = 'A' and val between 0 and 100) as cat_a,
count(1) filter (where category = 'B' and val between 0 and 125) as cat_b,
count(1) filter (where category = 'C' and val = 5) as cat_c
from sample
where ts >= pts and ts < pts + interval '10 seconds'
) lat;
period_start | period_end | cat_a | cat_b | cat_c |
---|---|---|---|---|
2018-01-01 08:00:00 | 2018-01-01 08:00:10 | 2 | 2 | 1 |
2018-01-01 08:00:10 | 2018-01-01 08:00:20 | 0 | 0 | 0 |
2018-01-01 08:00:20 | 2018-01-01 08:00:30 | 0 | 0 | 0 |
2018-01-01 08:00:30 | 2018-01-01 08:00:40 | 0 | 0 | 0 |
2018-01-01 08:00:40 | 2018-01-01 08:00:50 | 0 | 0 | 0 |
2018-01-01 08:00:50 | 2018-01-01 08:01:00 | 0 | 0 | 0 |
2018-01-01 08:01:00 | 2018-01-01 08:01:10 | 0 | 0 | 0 |
一排版很简单:
select min(ts) period_start,
max(ts) period_end,
count(1) filter (where category = 'A' and val between 0 and 100) as cat_a,
count(1) filter (where category = 'B' and val between 0 and 125) as cat_b,
count(1) filter (where category = 'C' and val = 5) as cat_c
from sample;
在澄清评论后添加
select * from (<the first version of the query here>) t where cat_c > 0;