众数需用窗口函数实现:先COUNT() OVER分组计频次,再ROW_NUMBER() OVER按频次降序排序,最后取rn=1;MySQL 8.0+、PostgreSQL、SQL Server均适用此法,不可用嵌套聚合或错误GROUP BY。

MySQL 8.0+ 怎么用 ROW_NUMBER() 和 COUNT() 找每组众数
直接说结论:众数不是内置聚合函数,必须靠窗口函数“先算频次、再排顺序、最后取首行”。核心思路是——对每个分组内值按出现次数降序,取 ROW_NUMBER() = 1 的那个值(注意:若有多个并列最高频,此法只返回一个,不自动去重或报错)。
常见错误是写成 GROUP BY group_col, value_col 后直接 ORDER BY COUNT(*) DESC LIMIT 1,这会报错或只返回全局第一条,根本没按组切分。
- 先用
COUNT(*) OVER (PARTITION BY group_col, value_col)算出每个(group_col, value_col)组合的频次 - 再套一层
ROW_NUMBER() OVER (PARTITION BY group_col ORDER BY cnt DESC, value_col ASC)——value_col ASC是为了在频次相同时有确定性排序,避免结果随机波动 - 最外层筛选
rn = 1即可得到每组众数(若需返回全部并列众数,把ROW_NUMBER换成RANK())
PostgreSQL 里用 MODE() WITHIN GROUP 真的能直接用?
能,但仅限于单字段简单场景,且有严格限制:它不支持 GROUP BY 后直接嵌套使用,也不能和窗口函数混用。你不能写 SELECT group_col, MODE() WITHIN GROUP (ORDER BY value_col) FROM t GROUP BY group_col —— 这语法合法,但语义是“整个表的众数”,不是“每组众数”。
真正可用的方式只有两种:
- 用
array_agg(value_col ORDER BY count(*) DESC, value_col ASC)[1]配合子查询(先GROUP BY group_col, value_col算频次,再聚合排序后取首元素) - 或者老实用
ROW_NUMBER()窗口写法,和 MySQL 逻辑一致,兼容性更好 - 注意:
MODE()对NULL值直接忽略,且遇到全NULL分组会返回NULL,不报错但容易漏判
SQL Server 中 TOP 1 WITH TIES 能不能简化众数查询?
可以,但只适用于单组场景或配合 CROSS APPLY。它本身不支持跨组,所以不能替代窗口函数。典型误用是写 SELECT TOP 1 WITH TIES value_col, COUNT(*) FROM t GROUP BY value_col ORDER BY COUNT(*) DESC —— 这返回的是整张表的众数值,不是按 group_col 分组后的结果。
正确做法是为每组单独执行频率统计:
- 用
CROSS APPLY对每个group_col值,查其对应子集的众数:(SELECT TOP 1 WITH TIES value_col FROM t t2 WHERE t2.group_col = t1.group_col GROUP BY value_col ORDER BY COUNT(*) DESC) - 性能隐患明显:数据量大时,
CROSS APPLY可能触发嵌套循环,比窗口函数慢一个数量级 - 如果某组所有
value_col都为NULL,TOP 1 WITH TIES会返回空结果,而非NULL,需额外COALESCE处理
为什么 HAVING COUNT(*) = MAX(COUNT(*)) 在任何 SQL 引擎里都报错?
因为聚合函数不能嵌套,COUNT(*) 是聚合结果,而 MAX(COUNT(*)) 试图对聚合结果再聚合,语法层面就非法。这不是引擎差异,是 SQL 标准硬性限制。
有人想绕过,比如先建临时表存频次,再查 MAX(cnt),再连回找匹配项——逻辑可行,但多出两层嵌套,可读性和维护性断崖下跌,还容易在并发更新时产生不一致。
- 窗口函数方案只需一层子查询,语义清晰,各主流引擎(MySQL 8.0+、PostgreSQL、SQL Server 2012+、Oracle)都支持
- 唯一要小心的是:不同引擎对
NULL在ORDER BY中的默认位置不同(PostgreSQL 默认NULLS LAST,MySQL 默认NULLS FIRST),若众数可能为NULL,务必显式写上NULLS LAST或NULLS FIRST - 别忘了加索引:
(group_col, value_col)联合索引能显著加速频次统计阶段

















