按连续日期分组,忽略 SQL 中的周末

Posted

技术标签:

【中文标题】按连续日期分组,忽略 SQL 中的周末【英文标题】:Grouping by contiguous dates, ignoring weekends in SQL 【发布时间】:2011-03-10 16:44:47 【问题描述】:

我正在尝试对连续的日期范围进行分组,以显示每个范围的最小和最大日期。到目前为止,我使用了与此类似的解决方案:http://www.sqlservercentral.com/articles/T-SQL/71550/ 但是我使用的是 SQL 2000,所以我必须进行一些更改。到目前为止,这是我的程序:

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

除了一个问题:周末,它完全按照我想要的方式工作。我的数据集没有周末日期的记录,这意味着找到的任何组最多为 5 天。例如,在下面的结果中,我希望最后 3 个组显示为一条记录,dateRangeStart 为 10/6,dateRangeEnd 为 10/20:

如果休息时间只是周末,我是否可以通过某种方式将其设置为忽略日期范围内的休息时间?

感谢您的帮助。

【问题讨论】:

为什么不创建一个带有周数列的永久日历表? @Martin 你能详细说明一下吗?我总是可以使用 datepart 获得周数,但我不明白这将如何帮助改变我的分组。 哦,对了,我看错了问题。 【参考方案1】:

已编辑

我不太喜欢我之前的想法。我认为这是一个更好的:

    根据要分组的一组日期中的第一个和最后一个日期,准备所有中间周末日期的列表。 将工作日期与周末日期一起插入,排序后,它们都将按照正常顺序分配rownum 值。

    使用您的方法查找连续范围并进行以下修改:

    1) 计算dateRangeStart时,如果是周末,则选择最近的下一个工作日;

    2) 对应dateRangeEnd,如果是周末日期,则选择最近的前一个工作日;

    3) 在为小组计算日期时,只选择工作日。

    从结果集中仅选择dates > 0 所在的行,从而消除仅由周末组成的组。

这是该方法的一个实现,假设一周从星期日开始(DATEPART 返回1),周末是星期日和星期六:

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;

【讨论】:

谢谢!这很好用。我曾考虑插入周末日期来解决范围问题,但我认为这会比这更困难。

以上是关于按连续日期分组,忽略 SQL 中的周末的主要内容,如果未能解决你的问题,请参考以下文章

Oracle sql查询按日期对连续记录进行分组

按名称分组的连续日期范围内的最小和最大日期

Sql获取连续日期的计数

我们如何在 SQL 中将连续数据分组为单个日期跨度?

关于一个DB2 按照日期分组的问题求解

按团队分组的基于赢、平和输的连续连胜/非连胜