T-SQL实现基于最近条件满足行的累计求和优化方案咨询
T-SQL实现基于最近条件满足行的累计求和优化方案咨询
你好,我来帮你解决这个T-SQL里的累计求和优化问题~
你的需求很明确:要计算从最近一次condition_col为TRUE的行(包含当前行如果它本身是TRUE的话)到当前行的col_to_sum累计值。之前用关联子查询的方案性能拉胯,是因为每一行都要执行两次嵌套子查询,相当于O(n²)的时间复杂度,数据量稍大就会很慢。你想改用窗口函数的思路完全正确,咱们可以用「分组+窗口求和」的方法来高效实现:
核心思路
先给每一行标记一个分组ID:从第一行开始,每遇到condition_col = TRUE的行,分组ID就加1。这样同一个分组内的所有行,都是属于最近一次TRUE行之后的连续行。然后在每个分组内做顺序累计求和,就能得到你要的结果。
具体SQL代码
SELECT ID, condition_col, col_to_sum, SUM(col_to_sum) OVER (PARTITION BY group_id ORDER BY ID) AS running_total_since_last_true FROM ( SELECT ID, condition_col, col_to_sum, -- 生成分组ID:每遇到TRUE就递增,把同一分段的行归为一组 SUM(CASE WHEN condition_col = 1 THEN 1 ELSE 0 END) OVER (ORDER BY ID) AS group_id FROM tbl ) AS grouped_data ORDER BY ID;
代码解释
- 内层子查询:用
SUM() OVER (ORDER BY ID)生成分组ID。每次遇到condition_col = TRUE,CASE语句返回1,累加后分组ID就会+1,这样所有在同一个TRUE分段内的行,分组ID都相同。 - 外层查询:用
SUM() OVER (PARTITION BY group_id ORDER BY ID),在每个分组内按ID顺序累计求和,正好就是从最近一次TRUE行到当前行的总和。
验证你的测试数据
用你给出的mock数据测试,结果完全符合预期:
- ID01(TRUE):group_id=1,累计和=10
- ID02(FALSE):group_id=1,累计和=10+8=18
- ID03(FALSE):group_id=1,累计和=18+12=30
- ID04(TRUE):group_id=2,累计和=5
- ...以此类推,完全匹配你想要的最后一列结果
性能优势
这个方案只需要扫描表两次(一次生成分组,一次求和),时间复杂度是O(n),相比你之前的关联子查询,几千行的数据应该能秒级返回结果,就算数据量再大,性能也会好很多。
另外你提到尝试过LAG(),这个函数确实不适合这种动态窗口的场景,因为它只能固定偏移量,没法动态引用最近的TRUE行,而分组+窗口求和的方法正好解决了这个问题。
备注:内容来源于stack exchange,提问作者Glen Hamblin
相关产品推荐
相关产品推荐

