Đây là một vấn đề khoảng trống và đảo. Trong trường hợp này, bạn có thể sử dụng lag()
để xem nơi bắt đầu của một hòn đảo và sau đó là tổng tích lũy.
Thao tác cuối cùng là một số tổng hợp (sử dụng các hàm cửa sổ):
SELECT p.*,
(Max(ends_on) OVER (PARTITION BY location_id, grp) - Min(starts_on) OVER (PARTITION BY location_id, grp) ) + 1 AS duration,
Array_agg(p.id) OVER (PARTITION BY location_id)
FROM (SELECT p.*,
Count(*) FILTER (WHERE prev_eo < starts_on - INTERVAL '1 day') OVER (PARTITION BY location_id ORDER BY starts_on) AS grp
FROM (SELECT id, starts_on, ends_on, location_id, holiday_or_vacation_type_id,
lag(ends_on) OVER (PARTITION BY location_id ORDER BY (starts_on)) AS prev_eo
FROM periods
) p
) p;