【问题标题】:Group islands of contiguous dates, including missing weekends连续日期的组岛,包括缺少的周末
【发布时间】:2020-12-19 07:42:01
【问题描述】:

我有一个包含某些操作日期的大型数据集,我正在尝试计算连续日期。环顾四周,我发现了这个:https://www.sqlservercentral.com/articles/group-islands-of-contiguous-dates-sql-spackle,它几乎是完美的,它正在做我正在寻找的东西。不幸的是,由于我的数据集,我有一个例外业务规则,我需要查询来执行:如果员工的最后日期是星期五,而下一个开始日期是最近的星期一,它应该将这些日期分组到同一个“岛”不增加天数。这是我对示例数据集的意思:

CREATE TABLE Actions    
   ([Employee] varchar(2), [ActionDate] date)    
;       

INSERT INTO Actions    
    ([Employee], [ActionDate])

VALUES    
    ('AA', '2019-01-03'),    
    ('AA', '2019-01-04'),    
    ('AA', '2019-01-07'),    
    ('AA', '2019-01-08'),    
    ('BB', '2019-08-01'),    
    ('BB', '2019-08-02'),    
    ('BB', '2019-08-03'),    
    ('BB', '2019-08-04'),    
    ('BB', '2019-08-05'),    
    ('BB', '2019-08-06'),    
    ('CC', '2019-09-09'),    
    ('CC', '2019-09-10'),    
    ('CC', '2019-09-11'),    
    ('CC', '2019-09-12'),    
    ('CC', '2019-09-13'),    
    ('CC', '2019-09-16'),    
    ('CC', '2019-09-17'),    
    ('CC', '2019-09-18')    
;

我找到的查询更改了列以匹配示例:

WITH    
days As    
(    
SELECT Employee,    
       ActionDate,    
       DATEADD(dd, -ROW_NUMBER() OVER  (PARTITION BY Employee ORDER BY Employee, ActionDate), ActionDate) As grouping    
FROM Actions    
GROUP BY Employee, ActionDate    
)    
SELECT Employee,    
       MIN(ActionDate) AS ActionStart,    
       MAX(ActionDate) As ActionEnd,    
       DATEDIFF(dd,MIN(ActionDate),MAX(ActionDate))+1 As ActLength    
FROM days    
GROUP BY Employee, grouping    
ORDER BY Employee, ActionStart

结果是:

+-------+----------+-------------+------------+-----------+
| RowNr | Employee | ActionStart | ActionEnd  | ActLength |
+-------+----------+-------------+------------+-----------+
|     1 | AA       |  03.01.2019 | 04.01.2019 |         2 |
|     2 | AA       |  07.01.2019 | 08.01.2019 |         2 |
|     3 | BB       |  01.08.2019 | 06.08.2019 |         6 |
|     4 | CC       |  09.09.2019 | 13.09.2019 |         5 |
|     5 | CC       |  16.09.2019 | 18.09.2019 |         3 |
+-------+----------+-------------+------------+-----------+

在此示例中,员工 AA 的结束日期是 4.1.2019 星期五,而 7.1.2019 开始日期是最近的星期一。 CC 也有一个结束日期为 2019 年 9 月 13 日星期五,下一个开始日期是最近的星期一,2019 年 9 月 16 日。它应该在不增加 ActLength 的情况下“组合”这些日期。所以想要的结果是:

+-------+----------+-------------+------------+-----------+
| RowNr | Employee | ActionStart | ActionEnd  | ActLength |
+-------+----------+-------------+------------+-----------+
|     1 | AA       |  03.01.2019 | 08.01.2019 |         4 |
|     2 | BB       |  01.08.2019 | 06.08.2019 |         6 |
|     3 | CC       |  09.09.2019 | 18.09.2019 |         8 |
+-------+----------+-------------+------------+-----------+

有谁知道可以为这种 SQL 查询创建这样的规则吗?我试着环顾四周,通常人们想排除周末。非常感谢大家。

【问题讨论】:

  • 我建议将 DATEPART 与 wk 参数一起使用,这意味着您将获得周数 - 这就是您可以按周分组的方式,这将考虑 friday-next-monday @ 的情况987654322@

标签: sql sql-server count window-functions gaps-and-islands


【解决方案1】:

我发现使用lag() 和窗口总和来实现您想要的逻辑更容易:

select employee, min(actionDate) actionStart, max(actionDate) actionEnd, count(*) actionLength
from (
    select 
        a.*, sum(
            case when actionDate = dateadd(day, 1, lagActionDate) 
                or (actionDate = dateadd(day, 3, lagActionDate) and datename(weekday, actionDate) = 'Monday')
            then 0 else 1 end
        ) over(partition by employee order by actionDate) grp
    from (
        select 
            a.*, 
            lag(actionDate) over(partition by employee order by actionDate) lagActionDate
        from actions a
    ) a
) a
group by employee, grp

Demo on DB Fiddle

员工 |行动开始 |动作结束 |动作长度 :------- | :------------ | :--------- | ------------: 机管局 | 2019-01-03 | 2019-01-08 | 4 BB | 2019-08-01 | 2019-08-06 | 6 抄送 | 2019-09-09 | 2019-09-18 | 8

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    相关资源
    最近更新 更多