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时重置运行计数。
第一次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时重置运行计数。