postgresql原生不支持mode()聚合函数,9.5+需用group by+order by count(*) desc limit 1实现单众数;14+新增mode() within group要求列可排序且仅返回排序靠前的众数。

PostgreSQL 没有内置 MODE() 聚合函数
直接写 SELECT MODE(column) FROM table GROUP BY group_col 会报错:ERROR: function mode(integer) does not exist。PostgreSQL 从 14 开始才通过 pg_stat_statements 扩展间接支持众数计算,但原生不提供标准聚合函数。你需要手动构造或借助窗口函数+子查询实现。
用 GROUP BY + ORDER BY COUNT(*) DESC 取每组频次最高的值
这是最通用、兼容所有 PostgreSQL 版本(9.5+)的做法,本质是“先统计频次,再取 Top 1”。注意:若存在多个相同最高频次的值(即多众数),该方法只返回其中一个(由 ORDER BY ... LIMIT 1 的排序稳定性决定)。
实操建议:
- 用子查询或 CTE 先算出每组中各值的出现次数
- 对每个分组,按计数降序排列,并用
LIMIT 1截取众数 - 若需处理多众数,改用
RANK() OVER (PARTITION BY group_col ORDER BY COUNT(*) DESC),再筛选rank = 1
示例(单众数):
SELECT group_col,
(SELECT value_col
FROM t t2
WHERE t2.group_col = t1.group_col
GROUP BY value_col
ORDER BY COUNT(*) DESC
LIMIT 1) AS mode_value
FROM (SELECT DISTINCT group_col FROM t) t1;
PostgreSQL 14+ 可用 mode() WITHIN GROUP (ORDER BY ...)
这是真正意义上的聚合函数,但必须配合 WITHIN GROUP 子句,且仅支持有序类型(如 numeric、text),不接受任意表达式。它返回每组中「排序后中间位置出现最多的值」——实际行为更接近「加权中位众数」,并非严格频次众数。
关键限制:
-
mode() WITHIN GROUP (ORDER BY x)要求x可排序,且结果依赖排序顺序 - 若多个值频次相同,它返回排序靠前的那个(不是随机,但易被误判为“任意一个”)
- 不能用于
GROUP BY外的上下文,也不能嵌套
示例(仅适用于数值/文本列):
SELECT group_col,
MODE() WITHIN GROUP (ORDER BY value_col) AS mode_value
FROM t
GROUP BY group_col;
性能和边界情况要特别小心
众数计算天然需要全量扫描+计数,在大数据集上比 AVG() 或 MAX() 昂贵得多。容易踩的坑包括:
- 忽略
NULL值:默认COUNT(*)统计所有行,COUNT(value_col)才跳过NULL;众数通常应排除NULL,否则可能被误选 - 字符串比较区分大小写或区域设置:例如
'A'和'a'在en_US.utf8下是不同值,影响频次统计 - 在
mode() WITHIN GROUP中对非有序类型(如jsonb)使用会直接报错:ERROR: argument of mode() must be sortable
没有银弹。如果业务要求严格多众数、高并发或实时响应,最好把频次统计逻辑移到应用层,或预计算到物化视图中。











