检查是否存在连续的日期间隔

han*_*ank 6 postgresql window-functions gaps-and-islands

我在 PostgreSQL 中有一个表,它描述了一些具有开始日期和结束日期的事件:

CREATE TABLE my_table
(
  event_id serial NOT NULL,
  start_date timestamp without time zone NOT NULL,
  end_date timestamp without time zone NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

单个事件可能与前一个和下一个事件重叠。在下表中,4 个事件中的前 3 个形成连续的时间间隔:

1   '2015-04-02 22:09:03'   '2015-04-02 22:19:05'
2   '2015-04-02 22:17:38'   '2015-04-02 22:27:38'
3   '2015-04-02 22:25:21'   '2015-04-02 22:36:23'
4   '2015-04-02 22:45:23'   '2015-04-02 22:55:23'
Run Code Online (Sandbox Code Playgroud)

是否可以编写一个查询来检查两个给定日期之间是否存在连续的日期间隔?

我想要一些类似的东西:

select ...
from my_table
where start_date > '2015-04-02' and end_date < '2015-04-06'
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 5

首先,我们组合重叠的区间以找到区间的所有连续“岛”:

with c as
  ( select *, max(end_date) over (order by start_date
                                  rows between unbounded preceding
                                           and 1 preceding)
                as previous_max
    from my_table
  )
select start_date, 
       coalesce(lead(previous_max) over (order by start_date),
                (select max(end_date) from my_table)
               ) as end_date
from c 
where previous_max < start_date 
   or previous_max is null ;
Run Code Online (Sandbox Code Playgroud)

之后,很容易检查给定的间隔是否完全被发现的连续岛屿之一包围。

   with c as
  ( select *, max(end_date) over (order by start_date
                                  rows between unbounded preceding
                                           and 1 preceding)
                as previous_max
    from my_table
  ) ,
cont as
  ( select start_date, 
           coalesce(lead(previous_max) over (order by start_date),
                    (select max(end_date) from my_table)
                   ) as end_date
    from c 
    where previous_max < start_date 
       or previous_max is null  
   )
select *
from cont
where tsrange(start_date, end_date)
       @>                             -- contains
      tsrange('2015-04-02 22:10:00', '2015-04-02 22:30:00') 
limit 1 ;
Run Code Online (Sandbox Code Playgroud)

SQLfiddle测试