Interesting situation. For anyone else trying to help, here's some DDL and DML:create table tmp (pk int primary key, DateField datetime)insert into tmpselect 1, '2/12/2006' union allselect 2,'02/13/2006' union allselect 3,'02/14/2006' union allselect 4,'02/15/2006' union allselect 5,'02/17/2006' union allselect 6,'02/19/2006' union allselect 7,'02/20/2006' union allselect 8,'02/22/2006' union allselect 9,'02/24/2006' union allselect 10,'02/25/2006' union allselect 11,'02/26/2006' union allselect 12,'02/27/2006' union allselect 13,'02/28/2006'My first instinct was to apply the methodology I presented in my article on detecting streaks in your data, which you can see here: http://www.sqlteam.com/item.asp?ItemID=12654However, the existing data that you have doesn't quite work for that. We can "pad" the data by adding at least 1 row between two dates by doing something like this:select DateField, max([Exists]) as [Exists]from( select DateField, 1 as [Exists] from tmp union all select DateField+1,0 from tmp) agroup by DateField
That returns, for your data:DateField Exists ------------------------------------------------------ ----------- 2006-02-12 00:00:00.000 12006-02-13 00:00:00.000 12006-02-14 00:00:00.000 12006-02-15 00:00:00.000 12006-02-16 00:00:00.000 02006-02-17 00:00:00.000 12006-02-18 00:00:00.000 02006-02-19 00:00:00.000 12006-02-20 00:00:00.000 12006-02-21 00:00:00.000 02006-02-22 00:00:00.000 12006-02-23 00:00:00.000 02006-02-24 00:00:00.000 12006-02-25 00:00:00.000 12006-02-26 00:00:00.000 12006-02-27 00:00:00.000 12006-02-28 00:00:00.000 12006-03-01 00:00:00.000 0(18 row(s) affected)
Now we have a format that works with my article. But it will be pretty inefficient, depending on how much data you have. Counting things "consecutively" in a set-based language like SQL isn't always easy.So, with that sql I gave you, create a view from it. Call it whatever you want, but I will refer to it as "TempView" in the following code. Once that is done, you read my article and apply the technique shown on the view we created to produce the following:select Min(DateField) as Start, Max(DateField) as [End], count(*) as DateCountfrom(select a.*, (select count(*) from TempView b where b.[Exists] <> a.[Exists] and b.DateField <= a.DateField) as RunGroupfrom TempView a) awhere [Exists] = 1group by RunGroup
Note the filter on [Exists]=1 -- we don't want to see the "blanks" that we padded in order to calculate the runs. The above returns everything, even "runs" that only have 1 consecutive date: Start End DateCount------------------- ------------------------- ----------- 2006-02-12 2006-02-15 42006-02-17 2006-02-17 12006-02-19 2006-02-20 22006-02-22 2006-02-22 12006-02-24 2006-02-28 5(5 row(s) affected)
So, by looking at the count(*) -- the DateCount column -- we see that the 1's are the dates that are non-consectutive, and anything >1 is that many consectutive dates.You also want to return a PatchID it appears, so we need to put the results into a temp table and let an identity calculate that. Our Final SQL, then, becomes:select identity(int, 1,1) as PatchID, Min(DateField) as PatchStartDate, Max(DateField) as PatchEndDateinto #tmpfrom( select a.*, (select count(*) from TempView b where b.[Exists] <> a.[Exists] and b.DateField <= a.DateField) as RunGroup from TempView a) awhere [Exists] = 1group by RunGrouphaving count(*) >1order by Min(DateField)select * from #tmp
which returns:PatchID Start End ----------- ---------------------- ------------------ 1 2006-02-12 2006-02-15 2 2006-02-19 2006-02-20 3 2006-02-24 2006-02-28 (3 row(s) affected)
which are the result you want. To see non-consecutive dates, you use a similiar SELECT but filter for Count(*) = 1.As mentioned, for a lot of rows, this will be inefficient. But it does make for an interesting challenge and you'll learn a heck of a lot about sql if you can follow all this.