SQL窗口函数处理含NULL值的分组累计计数问题
解决带NULL分组的累计计数需求
看起来你需要对包含NULL年份的数据集做特殊分组的累计统计,我来帮你梳理出正确的实现方式:
需求回顾
你有如下原始数据集:
| year | id |
|---|---|
| NULL | 123 |
| NULL | 124 |
| NULL | 125 |
| 1932 | 126 |
| 1932 | 127 |
| 1933 | 128 |
| 1933 | 129 |
| 1934 | 130 |
需要达成的目标是:
- 把
year为NULL的记录归为一组,统计该组的记录数 - 非
NULL的year按各自年份分组,并且从最早年份开始累计计数 - 最终得到这样的结果:
| year | count |
|---|---|
| NULL | 3 |
| 1932 | 2 |
| 1933 | 4 |
| 1934 | 5 |
你的思路调整
你尝试用UNION结合窗口函数的方向是对的,但需要先完成分组统计,再分别处理NULL组和非NULL组的累计逻辑,避免直接在原始表上操作导致的计数偏差。
正确的SQL实现
这里提供两种方案,分别对应不同的累计逻辑,你可以根据自己的真实需求选择:
方案1:匹配你给出的预期结果(NULL组单独统计,非NULL组内部累计)
这个方案会让NULL组只统计自身数量,非NULL年份从最早开始累计求和:
-- 处理NULL分组的单独计数 SELECT year, COUNT(id) AS count FROM data WHERE year IS NULL GROUP BY year UNION ALL -- 处理非NULL年份的累计计数 WITH non_null_grouped AS ( SELECT year, COUNT(id) AS group_count FROM data WHERE year IS NOT NULL GROUP BY year ORDER BY year ASC ) SELECT year, SUM(group_count) OVER (ORDER BY year ASC) AS count FROM non_null_grouped -- 最终排序,确保NULL排在最前面 ORDER BY CASE WHEN year IS NULL THEN 0 ELSE 1 END, year ASC;
代码说明:
- 第一部分单独提取NULL组,统计该组的总记录数
- 第二部分先对非NULL年份分组统计每个年份的记录数,再用窗口函数
SUM() OVER()按年份升序计算累计值 - 最后通过
ORDER BY确保NULL结果排在最前面,非NULL年份按时间顺序排列
方案2:全量累计(包含NULL组的数量)
如果你实际需要的是从NULL组开始的全量累计(比如1932的count应该是3+2=5),可以用这个方案:
WITH all_grouped AS ( SELECT year, COUNT(id) AS group_count FROM data GROUP BY year ORDER BY CASE WHEN year IS NULL THEN 0 ELSE 1 END, year ASC ) SELECT year, SUM(group_count) OVER (ORDER BY CASE WHEN year IS NULL THEN 0 ELSE 1 END, year ASC) AS count FROM all_grouped;
这个方案会先把所有数据按year分组,再基于分组结果做全量累计,最终结果会是:
| year | count |
|---|---|
| NULL | 3 |
| 1932 | 5 |
| 1933 | 7 |
| 1934 | 8 |
验证结果
执行方案1的SQL后,就能得到你预期的累计计数结果啦。
内容的提问来源于stack exchange,提问作者Anthony
相关产品推荐
相关产品推荐

