POSTGRESQL group by for 间隔

问题描述

我有一个查询,其中我有一个单位打开电灯开关的时间,包括打开(开始)时间和关闭(结束)时间。

我想知道有多少个电灯开关打开,有人知道我该怎么做吗?

示例查询

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
)

使用范围重叠&&运算符连接回原始表并聚合:

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,'[)')
        and l.flat = a.flat
 where a.end_ is not null
 group by a.flat,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

Working fiddle