我正在尝试在 MS SQL Server 中创建 60 天日期窗口组。每个组的起始索引点需要与新的 60 天周期的“开始”相关。
例如,下面的人 A 有七个事件,其开始和结束日期如下。
Event #1 在组 3/6/2018 (1/5/2018 + 60)
事件 #2 也在第 3/6/2018 组中,因为该事件在第一个 60 天窗口内 (2/2/2018 <=3/6/2018)
事件 #3 在 8/29/2018 组(6/5/2019 的开始日期在第一个 60 天窗口之外,因此新的 60 天窗口开始(6/30/2018 + 60)
A B C D E
1 Individual Event StartDate EndDate Groups
2 Person A Event #1 1/1/2018 1/5/2018 3/6/2018
3 Person A Event #2 2/2/2018 2/13/2018 3/6/2018
4 Person A Event #3 6/5/2018 6/30/2018 8/29/2018
5 Person A Event #4 9/5/2020 9/5/2020 11/4/2020
6 Person A Event #5 3/3/2021 3/5/2021 5/4/2021
7 Person A Event #7 4/1/2021 4/5/2021 5/4/2021
在 Excel 中,这可以通过运行以下公式来完成。
单元格 E2 = D2 + 60 单元格 E3 = IF(C3 <= E2,E2,D3+60) Cells E4:E7 = Dragging the formula from E3 down
服务端有公式可以完成这个分组吗?
我尝试运行下面的命令,但随后遇到了滞后函数的问题 1) 无法排除 NULL 值和 2) 无法像在 Excel 中那样替换上一行中找到的值。
WITH Part1 AS (
SELECT t.* ,CASE WHEN LAG(t.EndDate) OVER (PARTITION BY t.Individual ORDER BY t.EndDate) IS NULL THEN DATEADD(d,60,t.EndDate) ELSE NULL END AS Ref
FROM Table t
), Part2 AS (
SELECT p1.* ,CASE WHEN LAG(p1.Ref) OVER(PARTITION BY p1.Individual ORDER BY (t.EndDate) IS NOT NULL THEN p1.Ref WHEN p1.StartDate <= LAG(p1.Ref) OVER(PARTITION BY p1.Individual ORDER BY (t.EndDate) THEN LAG(p1.Ref) OVER(PARTITION BY p1.Individual ORDER BY (t.EndDate) ELSE DATEADD(d,60,p1.EndDate) END AS Groups
FROM Part1 AS p1
)
编辑:
A B C D E F
1 Individual Event StartDate EndDate Expected Actual
2 Person A Event #1 8/10/2020 8/13/2020 10/12/2020 10/12/2020
3 Person A Event #2 10/16/2020 10/18/2020 12/17/2020 12/17/2020
4 Person A Event #3 10/20/2020 10/23/2020 12/17/2020 12/17/2020
5 Person A Event #4 12/20/2020 12/22/2020 2/20/2021 12/17/2020
6 Person A Event #5 12/27/2020 12/28/2020 2/20/2021 12/17/2020
7 Person A Event #6 1/16/2021 1/18/2021 2/20/2021 12/17/2020
这是一个可能的解决方案:
SELECT Individual, Event
, CAST(startdate AS DATE) AS StartDate
, CAST(enddate AS DATE) AS EndDate
, CAST(Groups AS DATE) AS Expected
INTO #t
FROM (
VALUES (N'Person A','Event #1','1/1/2018','1/5/2018' ,'3/6/2018')
, (N'Person A','Event #2','2/2/2018','2/13/2018','3/6/2018')
, (N'Person A','Event #3','6/5/2018','6/30/2018','8/29/2018')
, (N'Person A','Event #4','9/5/2020','9/5/2020' ,'11/4/2020')
, (N'Person A','Event #5','3/3/2021','3/5/2021' ,'5/4/2021')
, (N'Person A','Event #7','4/1/2021','4/5/2021' ,'5/4/2021')
) t (Individual,Event,StartDate,EndDate,Groups)
select *
, DATEADD(DAY, 60, (
SELECT TOP 1 prev.Enddate
FROM #t prev
WHERE prev.Individual = t.Individual
AND DATEADD(DAY, 60, prev.enddate) > t.StartDate
ORDER BY prev.EndDate)
) AS GroupActual
FROM #t t
首先,我将字符串转换为适当的数据类型。
然后,对于每一行,获取对应于分组逻辑的第一个 EndDate,即。在当前行的 StartDate 的 60 天内。总会有至少一场比赛,要么是某个先前的日期,要么是与自己的比赛,这会创建新的“组”。
最后,我在这个日期上加上 60 天来创建分组日期。
编辑:
从上一个开始按60天分组的版本:
SELECT *
, MAX(DATEADD(DAY, 60, EndDate)) OVER(PARTITION BY Individual, grouping) AS GroupActual
FROM (
SELECT *
, SUM(matchingDays) OVER(PARTITION BY Individual ORDER BY StartDate) AS grouping
FROM (
SELECT *
, CASE WHEN DATEDIFF(DAY, lag(enddate, 1, StartDate) OVER(PARTITION BY Individual ORDER BY StartDate), StartDate) < 60 THEN 0 ELSE 1 END AS matchingDays
FROM #t t
) x
) x
这个使用 LAG 来获取之前的 Enddate。如果它在 60 天内,我不会增加一个标志来说明我们在哪个组。这允许我们创建一个滚动组计数器。每次我们超过 60 天,我们就开始一个新的组。
最后,您获得每个组的最大 EndDate 并向其添加 60 天。这都是非常标准的东西