sql标准及主流数据库不支持mode()函数,需用group by+count()+order by+limit(或top)查单个众数;多众数需子查询或rank()窗口函数;字符串拆分统计应避免硬编码,优先应用层处理。

SQL里没有MODE()函数,别被名字骗了
标准SQL(包括MySQL、PostgreSQL、SQL Server)都不原生支持 MODE() 函数。你如果在文档或报错里看到这个函数名,大概率是混淆了统计学概念和数据库语法,或者误用了某些分析型数据库(如某些版本的Presto/Trino有实验性支持,但不可靠)。真要找出现频率最高的值,得靠 COUNT() + 分组 + 排序组合实现。
用GROUP BY + ORDER BY + LIMIT查单个众数
这是最常用、兼容性最好的写法,适用于绝大多数场景(比如查销量最高的商品、访问最多的页面路径):
SELECT column_name, COUNT(*) AS cnt FROM table_name GROUP BY column_name ORDER BY cnt DESC LIMIT 1;
注意几点:
-
LIMIT 1只返回一个结果,如果有多个值并列最高频,会被随机截断——这不是bug,是预期行为 - MySQL 8.0+ 和 PostgreSQL 支持
LIMIT,SQL Server 要用TOP 1 - 如果字段含
NULL,默认会被分到同一组;需要排除就加WHERE column_name IS NOT NULL - 性能上,记得给
column_name加索引,否则GROUP BY可能全表扫描
查所有并列众数(不止一个最高频值)
当业务要求“所有出现次数等于最大频次的值”时,不能用 LIMIT,得用子查询或窗口函数:
用子查询(兼容性最好):
SELECT column_name, COUNT(*) AS cnt
FROM table_name
GROUP BY column_name
HAVING COUNT(*) = (
SELECT MAX(cnt) FROM (
SELECT COUNT(*) AS cnt
FROM table_name
GROUP BY column_name
) t
);
用窗口函数(MySQL 8.0+/PostgreSQL推荐):
SELECT column_name, cnt
FROM (
SELECT column_name, COUNT(*) AS cnt,
RANK() OVER (ORDER BY COUNT(*) DESC) AS rk
FROM table_name
GROUP BY column_name
) t
WHERE rk = 1;
RANK() 会把并列第一都标为1,比 ROW_NUMBER() 更适合众数场景;DENSE_RANK() 在这里效果一样,但语义不如 RANK() 直观。
字符串聚合去重后统计?小心隐式类型转换
遇到字段是逗号分隔的字符串(比如 "apple,banana,apple"),想统计其中每个元素的出现次数——这不属于直接查众数,而是先要拆分。别试图用 SUBSTRING_INDEX 或正则硬刚,容易漏数据或性能爆炸。
更稳妥的做法:
- 应用层拆分后批量插入临时表,再按正常流程
GROUP BY - 如果必须SQL内解决,MySQL 8.0+ 可用
JSON_TABLE配合REPLACE转成JSON数组,但代码冗长、可读性差 - PostgreSQL 直接用
STRING_TO_ARRAY()+UNNEST(),相对干净 - 任何情况下,都要注意大小写和前后空格——
TRIM(UPPER(column_name))往往比想象中更常需要
真正难的不是写出那条 SELECT,而是想清楚“最高频”在你的业务里是否允许忽略空值、是否要归一化大小写、是否接受近似结果。这些细节不定义清楚,再准的SQL也查不到对的答案。










