SQL 中的滚动总数超过 90 时重置为 0

Rolling total in SQL that Resets to 0 when going above 90

第一次post。在过去 6 个月中学习 SQL,因此感谢您的帮助。我的数据结构如下:

DECLARE @tmp4 as TABLE (
    AccountNumber int,
    Date            date,
    DateRank        int
)

INSERT INTO @tmp4
VALUES (001, '11/13/2018' , 1)
, (002, '12/19/2018', 2)
, (003, '1/23/2019' , 3)
, (004, '2/5/2019' , 4)
, (005, '3/10/2019' , 5)
, (006, '3/20/2019' , 6)
, (007, '4/8/2019' , 7)
, (008, '5/20/2019' , 8)

我需要对这些数据做的是计算一个滚动总数,一旦达到 90 天的阈值,该总数就会重置为 0。我已经使用 DateDiff 函数计算连续日期之间的 DateDiffs,并尝试使用 LAG 和其他 window 函数进行多项操作,但无法将其重置。目标是找到每 90 天只能出现一次的 "index visits"。所以我的计划是让一个字段在第一次访问时读取 0,并在第一次访问 90 天后的下一次停留时重置为 0,然后只拉取值为 0 的访问。

我尝试的一个解决方案对大多数集合都是正确的,但没有 return 上面集合的正确值(第 4 行和第 8 行应该从 "index visits" 开始)。 我期望此查询的结果是:

Account   Date         DateRank   RollingTotal

001     |'11/13/2018' | 1        | 0
002     |'12/19/2018' | 2        | 35
003     |'1/23/2019'  | 3        | 71
004     |'2/5/2019'   | 4        | 84
005     |'3/10/2019'  | 5        | 0  (not 117)
006     |'3/20/2019'  | 6        | 10 
007     |'4/8/2019'   | 7        | 29
008     |'5/20/2019'  | 8        | 71

感谢您的帮助。

这是我试过的代码:

DECLARE @tmp2 as TABLE
(EmrNumber      varchar(255)
, AdmitDateTime datetime
, DateRank      int
, LagDateDiff   int
, RunningTotal  int
)

INSERT INTO @tmp2

SELECT tmp1.EmrNumber
        , tmp1.AdmitDateTime
        , tmp1.DateRank
--, LAG(tmp1.AdmitDateTime) OVER(PARTITION BY tmp1.EmrNumber ORDER BY tmp1.DateRank) as NextAdmitDate
, -DATEDIFF(DAY, tmp1.AdmitDateTime, LAG(tmp1.AdmitDateTime) OVER(PARTITION BY tmp1.EmrNumber ORDER BY tmp1.DateRank)) LagDateDiff
, IIF((SELECT SUM(sumt.total)
        FROM (
                SELECT -DATEDIFF(DAY, tmpsum.AdmitDateTime, LAG(tmpsum.AdmitDateTime) OVER(PARTITION BY tmpsum.EmrNumber ORDER BY tmpsum.DateRank)) total
                FROM @tmp tmpsum
                WHERE tmp1.EmrNumber = tmpsum.EmrNumber 
                AND tmpsum.AdmitDateTime <= tmp1.AdmitDateTime
        ) sumt) IS NULL, 0, (SELECT SUM(sumt.total)
        FROM (
                SELECT -DATEDIFF(DAY, tmpsum.AdmitDateTime, LAG(tmpsum.AdmitDateTime) OVER(PARTITION BY tmpsum.EmrNumber ORDER BY tmpsum.DateRank)) total
                FROM @tmp tmpsum
                WHERE tmp1.EmrNumber = tmpsum.EmrNumber 
                AND tmpsum.AdmitDateTime <= tmp1.AdmitDateTime
        ) sumt) ) as RunningTotal 

FROM @tmp tmp1 

SELECT *
, CASE WHEN LagDateDiff >90 THEN 0
    WHEN RunningTotal = 0 THEN 0
    ELSE LAG(LagDateDiff) OVER(PARTITION BY EmrNumber ORDER BY DateRank) + RunningTotal END AS RollingTotal
FROM @tmp2

您需要对此进行递归查询,因为 运行 总数必须逐行迭代检查:

with cte as (
    select 
        Account, 
        Date, 
        DateRank, 
        0 RollingTotal
    from @tmp4
    where DateRank = 1
    union all
    select 
        t.Account, 
        t.Date,
        t.DateRank,
        case when RollingTotal + datediff(day, c.Date, t.Date) > 90
            then 0
            else RollingTotal  + datediff(day, c.Date, t.Date)
        end
    from cte c
    inner join @tmp4 t on t.DateRank = c.DateRank + 1
)
select * from cte

cte的锚点选择第一条记录(如DateRank所示)。然后,递归部分逐行处理,并在超过90时重置运行计数。