I'm attempting to group contiguous date ranges to show the minimum and maximum date for each range. So far I've used a solution similar to this one: http://www.sqlservercentral.com/articles/T-SQL/71550/ however I'm on SQL 2000 so I had to make some changes. This is my procedure so far:
create table #tmp
(
date smalldatetime,
rownum int identity
)
insert into #tmp
select distinct date from testDates order by date
select
min(date) as dateRangeStart,
max(date) as dateRangeEnd,
count(*) as dates,
dateadd(dd,-1*rownum, date) as GroupID
from #tmp
group by dateadd(dd,-1*rownum, date)
drop table #tmp
It works exactly how I want except for one issue: weekends. My data sets have no records for weekend dates, which means any group found is at most 5 days. For instance, in the results below, I would like the last 3 groups to show up as a single record, with a dateRangeStart of 10/6 and a d开发者_如何学PythonateRangeEnd of 10/20:
Is there some way I can set this up to ignore a break in the date range if that break is just a weekend?
Thanks for the help.
EDITED
I didn't like my previous idea very much. Here's a better one, I think:
- Based on the first and the last dates from the set of those to be grouped, prepare the list of all the intermediate weekend dates.
- Insert the working dates together with weekend dates, ordered, so they would all be assigned
rownum
values according to their normal order. Use your method of finding contiguous ranges with the following modifications:
1) when calculating
dateRangeStart
, if it's a weekend date, pick the nearest following weekday;2) accordingly for
dateRangeEnd
, if it's a weekend date, pick the nearest preceding weekday;3) when counting dates for the group, pick only weekdays.
Select from the resulting set only those rows where
dates > 0
, thus eliminating the groups formed only of the weekends.
And here's an implementation of the method, where it is assumed, that a week starts on Sunday (DATEPART
returns 1
) and weekend days are Sunday and Saturday:
DECLARE @tmp TABLE (date smalldatetime, rownum int IDENTITY);
DECLARE @weekends TABLE (date smalldatetime);
DECLARE @minDate smalldatetime, @maxDate smalldatetime, @date smalldatetime;
/* #1 */
SELECT @minDate = MIN(date), @maxDate = MAX(date)
FROM testDates;
SET @date = @minDate - DATEPART(dw, @minDate) + 7;
WHILE @date < @maxDate BEGIN
INSERT INTO @weekends
SELECT @date UNION ALL
SELECT @date + 1;
SET @date = @date + 7;
END;
/* #2 */
INSERT INTO @tmp
SELECT date FROM testDates
UNION
SELECT date FROM @weekends
ORDER BY date;
/* #3 & #4 */
SELECT *
FROM (
SELECT
MIN(date + CASE DATEPART(dw, date) WHEN 1 THEN 1 WHEN 7 THEN 2 ELSE 0 END)
AS dateRangeStart,
MAX(date - CASE DATEPART(dw, date) WHEN 1 THEN 2 WHEN 7 THEN 1 ELSE 0 END)
AS dateRangeEnd,
COUNT(CASE WHEN DATEPART(dw, date) NOT IN (1, 7) THEN date END) AS dates,
DATEADD(d, -rownum, date) AS GroupID
FROM @tmp
GROUP BY DATEADD(d, -rownum, date)
) s
WHERE dates > 0;
精彩评论