SQL Server 2012如何实现非负待办作业滚动总计计算
解决方案
不需要使用游标,使用SQL Server 2012支持的递归公共表表达式(CTE)即可实现该逻辑,性能优于游标实现。
你之前使用的普通累加窗口函数无法满足需求的原因是:窗口累加会直接计算全量的总到期数减去总Slots数,无法处理中间步骤出现负数时重置为0的逻辑,而这个重置操作会影响后续所有周的计算结果,必须通过逐行依赖上一步计算结果的逻辑实现。
完整实现代码
-- 测试样例表,可替换为你自己的业务表 DECLARE @TaskTable TABLE ( Week DATE, Slots INT, Due INT ); INSERT INTO @TaskTable VALUES ('2021-08-23',0,1), ('2021-08-30',2,3), ('2021-09-06',5,2), ('2021-09-13',1,4); WITH SortedData AS ( -- 按周排序生成行号,用于递归逐行计算 SELECT Week, Slots, Due, ROW_NUMBER() OVER (ORDER BY Week) AS rn FROM @TaskTable ), RecursiveTotal AS ( -- 锚点成员:计算第一周的待办总计 SELECT Week, Slots, Due, rn, IIF(Due - Slots > 0, Due - Slots, 0) AS Total FROM SortedData WHERE rn = 1 UNION ALL -- 递归成员:逐行计算后续每周的待办总计,依赖上一周的计算结果 SELECT s.Week, s.Slots, s.Due, s.rn, IIF(r.Total + s.Due - s.Slots > 0, r.Total + s.Due - s.Slots, 0) AS Total FROM SortedData s INNER JOIN RecursiveTotal r ON s.rn = r.rn + 1 ) SELECT Week, Slots, Due, Total FROM RecursiveTotal ORDER BY rn;
补充说明
- 如果你的数据行数超过100行,需要在查询末尾添加
OPTION (MAXRECURSION 0)来解除默认的递归深度限制,0代表无递归深度限制,也可以设置为和你实际最大周数匹配的数值。 - 如果确实需要使用游标实现,建议使用快进只读游标,这类游标是SQL Server中性能最优的游标类型,适合这种单方向遍历、只读的计算场景,实现逻辑和你给出的JS逻辑完全一致:初始化Total变量为0,逐行遍历按周排序的数据集,依次计算每行的Total值后更新到表中即可。
内容的提问来源于stack exchange,提问作者JHW
相关产品推荐
相关产品推荐

