正确做法是先group by,再用count()和sum(count()) over()计算占比;老版本用标量子查询(select count(*) from t);多级占比需partition by对齐业务层级;null分组需特别处理。

GROUP BY 后直接用 COUNT(*) / SUM(COUNT(*)) OVER() 计算占比
分组后算百分比,核心是「分子是当前组的行数,分母是全表总行数」。不能写 COUNT(*) / COUNT(*),也不能在子查询里反复查总数——既慢又易错。正确做法是用窗口函数 SUM(COUNT(*)) OVER() 拿到总行数,再做除法。
常见错误现象:ERROR: column "xxx" must appear in the GROUP BY clause or be used in an aggregate function,这是因为没把窗口函数放在聚合之后或位置不对。
- 必须先
GROUP BY,再在SELECT里用COUNT(*)和窗口函数配合 - 分母用
SUM(COUNT(*)) OVER(),不是COUNT(*) OVER()—— 后者对每行都返回相同值,但语义不清晰且在某些数据库(如 MySQL 8.0 前)不支持 - 结果是小数,建议乘 100 并用
ROUND(..., 2)控制精度,避免浮点误差干扰阅读
SELECT category, COUNT(*) AS cnt, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) AS pct FROM products GROUP BY category;
MySQL 5.7 或旧版 PostgreSQL 怎么绕过窗口函数限制
这些版本不支持在聚合中嵌套窗口函数,SUM(COUNT(*)) OVER() 会报错。得用子查询或 JOIN 拿总行数,但要注意关联方式和 NULL 安全。
- 推荐用
(SELECT COUNT(*) FROM products)作为标量子查询,写在SELECT列表里,最简洁 - 避免用
LEFT JOIN (SELECT COUNT(*) AS total FROM products) t—— 如果分组结果为空,JOIN 会导致整行丢失 - 标量子查询在 WHERE 条件复杂时可能重复执行,但对占比计算这种轻量场景影响极小
SELECT category, COUNT(*) AS cnt, ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM products), 2) AS pct FROM products GROUP BY category;
按多列分组并算占「某一级别」的百分比(比如城市占省份的百分比)
这不是全表占比,而是“组内再分层”的占比。关键在于窗口函数的 PARTITION BY 要对齐业务层级:想算“每个省下各城市的占比”,就 PARTITION BY province;想算“每个城市里各类产品的占比”,就 PARTITION BY city。
- 分母必须用
SUM(COUNT(*)) OVER(PARTITION BY province),不能漏掉PARTITION BY - 如果同时需要全表占比和层级占比,可以写多个窗口函数,互不干扰
- 注意
GROUP BY的字段必须包含PARTITION BY中的所有列,否则窗口函数逻辑错位
SELECT province, city, COUNT(*) AS cnt, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(PARTITION BY province), 2) AS city_pct_in_province FROM sales GROUP BY province, city;
NULL 值参与分组时占比容易失真
GROUP BY 默认把所有 NULL 归为同一组,但用户常误以为它们被忽略或单独统计。如果字段有大量 NULL,这个“NULL 组”的占比可能远超预期,而其他组数值被稀释。
- 检查前先运行
SELECT COUNT(*) FROM table WHERE col IS NULL,确认 NULL 比例 - 若需排除 NULL,加
WHERE col IS NOT NULL;若需单独强调,保留分组并在 SELECT 中用CASE WHEN col IS NULL THEN 'Unknown' ELSE col END可读性更好 - 不要依赖
COALESCE(col, 'N/A')直接进 GROUP BY——它会把原本不同的 NULL 和空字符串混成一组
实际写的时候,先想清楚分母是谁:全表?某个维度?还是动态层级?选错分母比语法错误更难排查。窗口函数写法虽简洁,但老版本兼容性差;标量子查询看着土,但在各种环境里最稳。










