Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQL Date Range Split

Tags:

sql

date-range

Can you please let me know the SQL to split date ranges when they overlap?

Data (sample data with a date range and possibly other columns):

    Col1 FromDate ToDate
 1. 1    1/1/2008 31/12/2010
 2. 1    1/1/2009 31/12/2012
 3. 1    1/1/2009 31/12/2014

Output:

   Col1  From Date ToDate
1. 1     1/1/2008 31/12/2008 (from row 1 above)
2. 1     1/1/2009 31/12/2010 (from rows 1,2 and 3 above)
3. 1     1/1/2011 31/12/2012 (from rows 2 and 3 above)
4. 1     1/1/2013 31/12/2014 (from row 3 above)
like image 576
user26309 Avatar asked Oct 08 '08 22:10

user26309


People also ask

How do I pass between two dates in SQL?

To find the difference between dates, use the DATEDIFF(datepart, startdate, enddate) function.

Can Between be used for dates in SQL?

The SQL BETWEEN OperatorThe values can be numbers, text, or dates. The BETWEEN operator is inclusive: begin and end values are included.


2 Answers

This should do the trick (MySQL dialect, but easily adaptable)

Initial setup

SQL query: SELECT * FROM `test` LIMIT 0, 30 ;
Rows: 3
start       end
2008-01-01  2010-12-31
2009-01-01  2012-12-31
2009-01-01  2014-12-31

Query

SELECT 
  `start` , min( `end` )
FROM (
  SELECT t1.start, t2.end
  FROM test t1, test t2
  WHERE t1.start < t2.end
  UNION
  SELECT t1.end + INTERVAL 1 DAY , t2.end
  FROM test t1, test t2
  WHERE t1.end + INTERVAL 1 DAY < t2.end
  UNION
  SELECT t1.start, t2.start - INTERVAL 1 DAY
  FROM test t1, test t2
  WHERE t1.start < t2.start - INTERVAL 1 DAY
) allRanges
GROUP BY `start`

Result

start       min( `end` )
2008-01-01  2008-12-31
2009-01-01  2010-12-31
2011-01-01  2012-12-31
2013-01-01  2014-12-31
like image 177
Sklivvz Avatar answered Sep 20 '22 07:09

Sklivvz


Skliwz's answer adapted for SQL Server:

DECLARE @DateTest TABLE 
(
    FromDate datetime,
    ToDate datetime 
)

insert into @DateTest (FromDate, ToDate)
(
select cast('1/1/2008' as datetime), cast('12/31/2010' as datetime)
union
select cast('1/1/2009' as datetime), cast('12/31/2012' as datetime)
union
select cast('1/1/2009' as datetime), cast('12/31/2014' as datetime)
)

SELECT 
  FromDate , min(ToDate)
FROM (
  SELECT t1.FromDate, t2.ToDate
  FROM 
    @DateTest t1, 
    @DateTest t2
  WHERE t1.FromDate < t2.ToDate

  UNION

  SELECT dateadd(DAY, 1, t1.ToDate), t2.ToDate
  FROM 
    @DateTest t1, 
    @DateTest t2
  WHERE dateadd(DAY, 1, t1.ToDate) < t2.ToDate
) allRanges
group by FromDate
like image 39
Even Mien Avatar answered Sep 22 '22 07:09

Even Mien