Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interesting SQL puzzle

Without loops or cursors, how do you take a list of date intervals and turn them into a string of 1s and 0s such that:

  • each bit represents each day from min(all the dates) to max(all the dates)
  • the bit is 1 if that day falls inside any of the date intervals
  • the bit is 0 if that day does not fall in any of the intervals

So for example, if the intervals were:

  • 1/1/2011 to 1/2/2011
  • 1/4/2011 to 1/5/2011

Then the SQL you write should output 11011. Here is a setup script you could use:

declare @TimeSpan table
(
    start datetime
    ,finish datetime
)

-- this is a good data set, with overlapping and non-overlapping time spans
insert into @TimeSpan values ('02/02/2010', '02/02/2010')
insert into @TimeSpan values ('02/03/2010', '02/03/2010')
insert into @TimeSpan values ('02/04/2010', '02/05/2010')
insert into @TimeSpan values ('02/05/2010', '02/06/2010')
insert into @TimeSpan values ('02/07/2010', '02/09/2010')
insert into @TimeSpan values ('02/08/2010', '02/08/2010')
insert into @TimeSpan values ('02/08/2010', '02/10/2010')
insert into @TimeSpan values ('02/14/2010', '02/16/2010')

-- for this set of data, the output string would be 111111111000111
like image 264
Milimetric Avatar asked Apr 15 '11 17:04

Milimetric


1 Answers

DECLARE @Result VARCHAR(MAX), @start DATETIME

SELECT @start= MIN(start) ,
       @Result =REPLICATE('0',1+DATEDIFF(DAY,MIN(start),MAX(finish)))
FROM @TimeSpan

SELECT @Result = STUFF(@Result,
                       DATEDIFF(DAY,@start,start)+1,
                       DATEDIFF(DAY,start,finish)+1,
                       REPLICATE('1',1+DATEDIFF(DAY,start,finish)))
FROM @TimeSpan 

SELECT @Result       
like image 192
Martin Smith Avatar answered Oct 28 '22 18:10

Martin Smith