POSTGRESQL 分组依据间隔
POSTGRESQL group by for interval
我有一个查询,其中我有一个公寓里电灯开关的时间,有开(开始)时间和关(结束)时间。
我想知道有多少个电灯开关,有人知道我该怎么做吗?
示例查询:
Select Flat, ID_light, start, end, 1 as ON
from lights
i/o的例子:
输入数据:
Flat Id Light Start End On
1 1 01/01/2021 00:00:15 01/01/2021 00:59:00 1
1 2 01/01/2021 00:00:15 01/01/2021 01:59:00 1
2 1 01/01/2021 00:00:15 01/01/2021 00:01:15 1
2 1 01/01/2021 00:02:00 01/01/2021 01:00:00 1
2 2 01/01/2021 00:00:00 01/01/2021 08:00:00 1
文本输出:
Flat Start End Lights On
1 01/01/2021 00:00:15 01/01/2021 00:59:00 2
1 01/01/2021 00:59:00 01/01/2021 01:59:00 1
2 01/01/2021 00:00:00 01/01/2021 00:00:15 1
2 01/01/2021 00:00:15 01/01/2021 00:01:15 2
2 01/01/2021 00:01:15 01/01/2021 00:02:00 1
2 01/01/2021 00:02:00 01/01/2021 01:00:00 2
2 01/01/2021 01:00:00 01/01/2021 08:00:00 1
range
数据类型简化了这一点。
获取所有单位和时间:
with times as (
select flat, start as ts from lights
union
select flat, end_ from lights
),
使用 lead()
:
为每个间隔构造行
all_ivals as (
select flat, ts as start,
lead(ts) over (partition by flat
order by ts) as end_
from times
)
加入原始 table 并使用范围重叠 &&
运算符聚合:
select a.flat, a.start, a.end_, count(*) as lights_on
from all_ivals a
join lights l
on tsrange(l.start, l.end_, '[)') && tsrange(a.start, a.end_, '[)')
and l.flat = a.flat
where a.end_ is not null
group by a.flat, a.start, a.end_
order by a.flat, a.start
;
结果:
flat start end_ lights_on
1 2021-01-01 00:00:15 2021-01-01 00:59:00 2
1 2021-01-01 00:59:00 2021-01-01 01:59:00 1
2 2021-01-01 00:00:00 2021-01-01 00:00:15 1
2 2021-01-01 00:00:15 2021-01-01 00:01:15 2
2 2021-01-01 00:01:15 2021-01-01 00:02:00 1
2 2021-01-01 00:02:00 2021-01-01 01:00:00 2
2 2021-01-01 01:00:00 2021-01-01 08:00:00 1
7 rows
我有一个查询,其中我有一个公寓里电灯开关的时间,有开(开始)时间和关(结束)时间。
我想知道有多少个电灯开关,有人知道我该怎么做吗?
示例查询:
Select Flat, ID_light, start, end, 1 as ON
from lights
i/o的例子:
输入数据:
Flat Id Light Start End On
1 1 01/01/2021 00:00:15 01/01/2021 00:59:00 1
1 2 01/01/2021 00:00:15 01/01/2021 01:59:00 1
2 1 01/01/2021 00:00:15 01/01/2021 00:01:15 1
2 1 01/01/2021 00:02:00 01/01/2021 01:00:00 1
2 2 01/01/2021 00:00:00 01/01/2021 08:00:00 1
文本输出:
Flat Start End Lights On
1 01/01/2021 00:00:15 01/01/2021 00:59:00 2
1 01/01/2021 00:59:00 01/01/2021 01:59:00 1
2 01/01/2021 00:00:00 01/01/2021 00:00:15 1
2 01/01/2021 00:00:15 01/01/2021 00:01:15 2
2 01/01/2021 00:01:15 01/01/2021 00:02:00 1
2 01/01/2021 00:02:00 01/01/2021 01:00:00 2
2 01/01/2021 01:00:00 01/01/2021 08:00:00 1
range
数据类型简化了这一点。
获取所有单位和时间:
with times as (
select flat, start as ts from lights
union
select flat, end_ from lights
),
使用 lead()
:
all_ivals as (
select flat, ts as start,
lead(ts) over (partition by flat
order by ts) as end_
from times
)
加入原始 table 并使用范围重叠 &&
运算符聚合:
select a.flat, a.start, a.end_, count(*) as lights_on
from all_ivals a
join lights l
on tsrange(l.start, l.end_, '[)') && tsrange(a.start, a.end_, '[)')
and l.flat = a.flat
where a.end_ is not null
group by a.flat, a.start, a.end_
order by a.flat, a.start
;
结果:
flat start end_ lights_on
1 2021-01-01 00:00:15 2021-01-01 00:59:00 2
1 2021-01-01 00:59:00 2021-01-01 01:59:00 1
2 2021-01-01 00:00:00 2021-01-01 00:00:15 1
2 2021-01-01 00:00:15 2021-01-01 00:01:15 2
2 2021-01-01 00:01:15 2021-01-01 00:02:00 1
2 2021-01-01 00:02:00 2021-01-01 01:00:00 2
2 2021-01-01 01:00:00 2021-01-01 08:00:00 1
7 rows