SQL中计算累计总额(running total)与平均值的技术问询
修正SQL代码实现累计总额与平均值计算
现有临时表数据
临时表#temp1包含Month、RecordTotalByMonth、Type、Product字段,数据如下:
| 月份 | 月度记录总数 | 类型 | 产品 |
|---|---|---|---|
| 1 | 10 | New | Wellness |
| 2 | 20 | New | Wellness |
| 3 | 30 | New | Wellness |
| 4 | 30 | New | Wellness |
| 1 | 15 | Average Claim Size | Wellness |
| 2 | 15 | Average Claim Size | Wellness |
| 3 | 30 | Average Claim Size | Wellness |
| 4 | 10 | Average Claim Size | Wellness |
| 1 | 10 | New | Accident |
| 2 | 20 | New | Accident |
| 3 | 30 | New | Accident |
| 4 | 30 | New | Accident |
| 1 | 15 | Average Claim Size | Accident |
| 2 | 15 | Average Claim Size | Accident |
| 3 | 30 | Average Claim Size | Accident |
| 4 | 10 | Average Claim Size | Accident |
需求规则
- 当
Product为'Wellness'或'Accident'且Type为'New'时,按月份计算累计总额(running total) - 当
Product为'Wellness'或'Accident'且Type为'Average Claim Size'时,计算该产品对应类型的平均值
期望结果
| 月份 | 月度记录总数 | 类型 | 产品 | Total or Average |
|---|---|---|---|---|
| 1 | 10 | New | Wellness | 10 |
| 2 | 20 | New | Wellness | 30 |
| 3 | 30 | New | Wellness | 60 |
| 4 | 30 | New | Wellness | 90 |
| 1 | 15 | Average Claim Size | Wellness | 20 |
| 2 | 15 | Average Claim Size | Wellness | 20 |
| 3 | 30 | Average Claim Size | Wellness | 20 |
| 4 | 20 | Average Claim Size | Wellness | 20 |
| 1 | 10 | New | Accident | 10 |
| 2 | 20 | New | Accident | 30 |
| 3 | 30 | New | Accident | 60 |
| 4 | 30 | New | Accident | 90 |
| 1 | 10 | Average Claim Size | Accident | 15 |
| 2 | 10 | Average Claim Size | Accident | 15 |
| 3 | 30 | Average Claim Size | Accident | 15 |
| 4 | 10 | Average Claim Size | Accident | 15 |
原代码问题分析
原代码存在两个核心问题:
- 计算
New类型的累计总额时,仅用partition by Product未按月份排序,无法实现累计效果,只会得到该产品的总合计值 - 计算
Average Claim Size类型的平均值时,partition by Type会把所有产品的该类型数据合并计算,不符合需求中按产品分组计算的要求
修正后的SQL代码
SELECT Month AS 月度, RecordTotalByMonth AS 月度记录总数, Type AS 类型, Product AS 产品, CASE -- 处理New类型的累计总额:按产品+类型分组,按月度排序累计求和 WHEN Type = 'New' THEN SUM(RecordTotalByMonth) OVER ( PARTITION BY Product, Type ORDER BY Month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) -- 处理Average Claim Size类型的平均值:按产品+类型分组计算整体平均值 WHEN Type = 'Average Claim Size' THEN AVG(RecordTotalByMonth * 1.0) OVER ( PARTITION BY Product, Type ) END AS [Total or Average] INTO New_table FROM #temp1 -- 过滤指定产品(若表中只有这两类产品可省略) WHERE Product IN ('Wellness', 'Accident') ORDER BY Product, Type, Month;
代码说明
- 累计总额部分:
PARTITION BY Product, Type确保每个产品的New类型单独累计,ORDER BY Month保证按月顺序计算,ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW明确累计范围是从第一条到当前行(部分SQL方言可省略此子句,默认即为累计逻辑) - 平均值部分:
PARTITION BY Product, Type按每个产品的该类型分组计算平均值,乘以1.0是为了避免整数除法导致精度丢失 - 一次性查询生成结果,无需分两次插入,逻辑更简洁且保证数据顺序
内容的提问来源于stack exchange,提问作者Tan Singh
相关产品推荐
相关产品推荐

