patternsqlMinor
Check if contiguous date interval exists
Viewed 0 times
contiguousintervaldateexistscheck
Problem
I have a table in PostgreSQL which describes some events that have a start date and an end date:
A single event may overlap the previous and the next one. In the following table the first 3 of 4 events form a contiguous time interval:
Is it possible to write a query that checks if a contiguous date interval between two given dates exists?
I would like to have something like:
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
)A single event may overlap the previous and the next one. In the following table the first 3 of 4 events form a contiguous time interval:
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'Is it possible to write a query that checks if a contiguous date interval between two given dates exists?
I would like to have something like:
select ...
from my_table
where start_date > '2015-04-02' and end_date < '2015-04-06'Solution
First, we combine intervals that overlap to find all the contiguous "islands" of the intervals:
After that, it's easy to check if a given interval in completely surrounded by one of the found contiguous islands.
Test at SQLfiddle
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 ;After that, it's easy to check if a given interval in completely surrounded by one of the found contiguous islands.
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 -- contains
tsrange('2015-04-02 22:10:00', '2015-04-02 22:30:00')
limit 1 ;Test at SQLfiddle
Code Snippets
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 ;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 ;Context
StackExchange Database Administrators Q#96974, answer score: 6
Revisions (0)
No revisions yet.