This query returns all gaps in the data that overlap with the given time range. Also covers leading, trailing or total (covering) gaps:
WITH input(t1, t2) AS (SELECT '2015-04-02 22:00'::timestamp
, '2015-04-02 23:00'::timestamp) -- t1 < t2
, gap AS (
SELECT max(end_date) OVER (ORDER BY start_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS start_gap
, start_date AS end_gap
, end_date -- for possible trailing gap
FROM my_table
WHERE end_date >= (SELECT t1 FROM input) -- exclude rows early
AND start_date <= (SELECT t2 FROM input)
)
SELECT start_gap, end_gap
FROM gap
WHERE end_gap > start_gap -- gap within time range
OR start_gap IS NULL AND end_gap > (SELECT t1 FROM input) -- leading gap
UNION ALL
SELECT max(end_date), NULL -- trailing gap
FROM gap
HAVING max(end_date) < (SELECT t2 FROM input)
UNION ALL
SELECT NULL, NULL -- total gap
WHERE NOT EXISTS (SELECT 1 FROM gap)
ORDER BY end_gap;
fiddle
If nothing is returned, the check succeeds:
checks if a contiguous date interval between two given dates exists?
Only needs a single scan over the base table and a single window function. Should be fast.
If you are not familiar with window functions, read this chapter of the manual.
Related:
About OVERLAPS
:
Function counting gaps
For a quick answer to your question without details, the query can be simplified. Also parameter handling is more convenient in a function:
CREATE OR REPLACE FUNCTION f_find_gaps(t1 timestamp, t2 timestamp)
RETURNS int
LANGUAGE sql AS
$func$
WITH gap AS (
SELECT max(end_date) OVER (ORDER BY start_date
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS start_gap
, start_date AS end_gap
, end_date -- for possible trailing gap & total gap
FROM my_table
WHERE end_date >= t1 -- exclude rows early
AND start_date <= t2
)
SELECT count(*)::int
+ CASE WHEN (SELECT max(end_date) >= t2 FROM gap) THEN 0 ELSE 1 END
-- covers trailing gap & total gap
FROM gap
WHERE end_gap > start_gap -- gap within time range
OR start_gap IS NULL AND end_gap > t1 -- leading gap
$func$;
Call:
SELECT f_find_gaps('2015-04-02 22:00', '2015-04-02 23:00');
fiddle
Returns the number of gaps. 0
means, your range is covered.