SQL如何实现分组统计间隔重置的连续月份计数?
连续月份计数重置最优实现方案
该需求属于SQL经典的「岛屿(连续序列)识别」场景,仅用标准窗口函数即可实现,时间复杂度为O(n),适配所有支持窗口函数的SQL引擎(MySQL 8.0+、PostgreSQL、SQL Server、Hive、Spark SQL等)。
核心逻辑
- 第一步:对每个Case Number下的记录按发生月份升序排序,生成唯一行号
- 第二步:将
Occurrence Month转换为总月数(年份*12 + 月份),减去第一步得到的行号,得到分组标记。连续的月份计算出的分组标记完全一致,出现间隔时分隔标记会自动变化 - 第三步:对每个Case Number和分组标记构成的小分组,再次按发生月份升序生成行号,就是需要的连续月份计数
完整实现代码
WITH rn_calc AS ( SELECT CaseNumber, OccurrenceMonth, -- 按Case分组生成行号 ROW_NUMBER() OVER(PARTITION BY CaseNumber ORDER BY OccurrenceMonth) AS rn FROM `table` ), group_calc AS ( SELECT CaseNumber, OccurrenceMonth, -- 计算连续分组标记 (LEFT(OccurrenceMonth,4)*12 + RIGHT(OccurrenceMonth,2)) - rn AS group_id FROM rn_calc ) SELECT CaseNumber, OccurrenceMonth, -- 分组内生成连续计数 ROW_NUMBER() OVER(PARTITION BY CaseNumber, group_id ORDER BY OccurrenceMonth) AS ConsecutiveMonths FROM group_calc ORDER BY CaseNumber, OccurrenceMonth;
示例计算验证
对应你提供的测试数据,各中间值计算结果如下:
| Case Number | Occurrence Month | rn | 总月数 | group_id | ConsecutiveMonths |
|---|---|---|---|---|---|
| 123 | 201801 | 1 | 24217 | 24216 | 1 |
| 123 | 201802 | 2 | 24218 | 24216 | 2 |
| 123 | 201803 | 3 | 24219 | 24216 | 3 |
| 123 | 201805 | 4 | 24221 | 24217 | 1 |
| 123 | 201806 | 5 | 24222 | 24217 | 2 |
如果你的OccurrenceMonth是日期类型,仅需将总月数计算逻辑替换为YEAR(OccurrenceMonth)*12 + MONTH(OccurrenceMonth)即可,整体逻辑无需调整。
内容的提问来源于stack exchange,提问作者mmghu
相关产品推荐
相关产品推荐

