如何在T-SQL中创建遇NULL值重置的累计求和列
需求:创建遇NULL重置的分区累计求和列
需要为数据集生成Running_T累计求和列,满足以下规则:
- 按
ID字段分区,每个ID单独计算累计 - 按
date字段保持顺序排序 - 每次遇到单个或连续多个
NULL值时,累计求和结果重置;且NULL对应的Running_T值也为NULL
期望结果如下:
| ID | date | value | Running_T |
|---|---|---|---|
| SA223 | 10/07/2018 | 3 | 3 |
| SA223 | 11/07/2018 | 6 | 9 |
| SA223 | 25/07/2018 | NULL | NULL |
| SA223 | 16/08/2018 | 11 | 11 |
| SA223 | 17/08/2018 | 9 | 20 |
| SA555 | 15/05/2019 | 4 | 4 |
| SA555 | 27/05/2019 | 13 | 17 |
| SA555 | 11/07/2019 | NULL | NULL |
| SA555 | 21/11/2019 | NULL | NULL |
| SA555 | 20/02/2020 | 4 | 4 |
| SA555 | 27/05/2020 | 1 | 5 |
| SA555 | 23/07/2020 | 2 | 7 |
尝试了以下代码,但无法正确处理NULL重置,还打乱了排序:
SELECT ID , date , value ,Running_T = SUM(value) OVER(PARTITION BY ID, (CASE WHEN [value] IS NOT NULL THEN [value] ELSE NULL END) ORDER BY [date]) FROM dim.event_data
解决方案
正确的思路是先为每个连续的非NULL区间创建分组标识,再基于分组计算累计求和:
WITH grouped_data AS ( SELECT ID, date, value, -- 生成分组标识:每个ID下,遇到NULL则分组编号递增,连续非NULL属于同一组 group_id = SUM(CASE WHEN value IS NULL THEN 1 ELSE 0 END) OVER (PARTITION BY ID ORDER BY date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) FROM dim.event_data ) SELECT ID, date, value, Running_T = CASE WHEN value IS NULL THEN NULL ELSE SUM(value) OVER (PARTITION BY ID, group_id ORDER BY date) END FROM grouped_data ORDER BY ID, date;
逻辑说明:
- 分组标识生成:通过
SUM(CASE WHEN value IS NULL THEN 1 ELSE 0 END)窗口函数,按ID分区、日期排序,累计到当前行的NULL数量。每遇到一个NULL,分组编号就加1,这样连续的非NULL行就会拥有相同的group_id,NULL行则会开启新的分组(但后续计算时会跳过这些行的累计)。 - 累计求和计算:基于
ID和group_id分区,按日期排序计算累计求和;同时通过CASE语句,将value为NULL的行的Running_T设为NULL,符合需求。
原代码问题分析:
原代码的PARTITION BY使用了value本身,这会把相同value的行分到同一组,完全不符合"连续非NULL区间"的分组逻辑,导致累计求和混乱,也无法正确处理NULL的重置需求。
内容的提问来源于stack exchange,提问作者Shedrack
相关产品推荐
相关产品推荐

