I have lets say a \"travel date\" and black out dates. I will split the travel date into pieces according to the black out dates.
Note: Travel Date can be between
This returns a discrete list of all dates that exist in the Travel Dates range but not in the Blackout Dates list, and then combines them using Oracle - Convert value from rows into ranges:
WITH traveldate AS
(SELECT TO_DATE('2011 01 04','YYYY MM DD') AS start_date
,TO_DATE('2011 12 11','YYYY MM DD') AS end_date FROM DUAL)
,blackout AS
(SELECT TO_DATE('2010 11 01','YYYY MM DD') AS start_date
,TO_DATE('2011 02 11','YYYY MM DD') AS end_date FROM DUAL
UNION ALL
SELECT TO_DATE('2011 01 20','YYYY MM DD') AS start_date
,TO_DATE('2011 02 15','YYYY MM DD') AS end_date FROM DUAL
UNION ALL
SELECT TO_DATE('2011 03 13','YYYY MM DD') AS start_date
,TO_DATE('2011 04 10','YYYY MM DD') AS end_date FROM DUAL
UNION ALL
SELECT TO_DATE('2011 03 20','YYYY MM DD') AS start_date
,TO_DATE('2011 06 29','YYYY MM DD') AS end_date FROM DUAL)
,days AS
(SELECT TO_DATE('2010 01 01','YYYY MM DD') + ROWNUM d
FROM DUAL CONNECT BY LEVEL <= 1000)
,base AS
(SELECT d AS n
FROM days, traveldate
WHERE d >= traveldate.start_date AND d <= traveldate.end_date
MINUS
SELECT d AS n
FROM days, blackout
WHERE d >= blackout.start_date AND d <= blackout.end_date
)
,lagged AS
(
SELECT n, LAG(n) OVER (ORDER BY n) lag_n FROM base
)
, groups AS
(
SELECT n, row_number() OVER (ORDER BY n) groupnum
FROM lagged
WHERE lag_n IS NULL OR lag_n < n-1
)
, grouped AS
(
SELECT n, (SELECT MAX(groupnum) FROM groups
WHERE groups.n <= base.n
) groupnum
FROM base
)
SELECT groupnum, MIN(n), MAX(n)
FROM grouped
GROUP BY groupnum
ORDER BY groupnum;
Result:
GROUPNUM MIN(N) MAX(N)
1 16/02/2011 12/03/2011
2 30/06/2011 11/12/2011