SQL Server 中的相对 60 天组

问题描述 投票:0回答:1

我正在尝试在 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
sql-server grouping date-range gaps-and-islands
1个回答
0
投票

这是一个可能的解决方案:

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 天。这都是非常标准的东西

© www.soinside.com 2019 - 2024. All rights reserved.