You can do this using the LEAD , LAG window functions available from SQL Server 2012 +:
;WITH CTE AS ( SELECT ID, LAG(DateEnd) OVER (PARTITION BY ID ORDER BY DateEnd) AS PrevEnd, DateStart, DateEnd, LEAD(DateStart) OVER (PARTITION BY ID ORDER BY DateEnd) AS NextStart FROM DatesTable ) SELECT ID, DateStart, DateEnd FROM ( -- Get interval right before current [DateStart, DateEnd] interval SELECT ID, CASE WHEN DateStart IS NULL THEN '20150101' WHEN DateStart > start THEN start ELSE NULL END AS DateStart, CASE WHEN DateStart IS NULL THEN '20151231' WHEN DateStart > start THEN DATEADD(d, -1, DateStart) ELSE NULL END AS DateEnd FROM CTE CROSS APPLY (SELECT COALESCE(DATEADD(d, 1, PrevEnd), '20150101')) x(start) -- If there is no next interval then get interval right after current -- [DateStart, DateEnd] interval (up-to end of year) UNION ALL SELECT ID, DATEADD(d, 1, DateEnd) AS DateStart, '20151231' AS DateEnd FROM CTE WHERE DateStart IS NOT NULl -- Do not re-examine [Null, Null] interval AND NextStart IS NULL -- There is no next [DateStart, DateEnd] interval AND DateEnd < '20151231' -- Current [DateStart, DateEnd] interval -- does not terminate on 31/12/2015 ) AS t WHERE t.DateStart IS NOT NULL ORDER BY ID, DateStart
The idea of ββthe above query is simple: for each interval [DateStart, DateEnd] we get a "non-working" interval right in front of it. If the interval following the current interval is missing, then also get a consecutive "idle" interval (if any).
Also note that I am assuming that if DateStart is NULL , then DateStart also NULL for the same ID .
Demo here
Giorgos betsos
source share