PostgreSQL 15 不支持内置 MODE() 函数,需手动实现众数计算:常用方法是 GROUP BY + COUNT + ROW_NUMBER() 嵌套查询,按频次降序排序并取首行,注意处理 NULL 和多众数场景。

PostgreSQL 15 没有内置 MODE() 聚合函数
直接写 SELECT MODE() FROM ... GROUP BY 会报错:ERROR: function mode() does not exist。PostgreSQL 直到 16 才正式引入 MODE() WITHIN GROUP(作为窗口聚合的变体),15 版本不支持。想在 15 里求众数,必须手动实现。
用 GROUP BY + COUNT + ROW_NUMBER() 手动找众数
核心思路:对每组数据统计频次 → 按频次降序排序 → 取排名第一的值(注意处理并列情况)。实际要分两层嵌套,外层确保每组只返回一行。
常见错误是漏掉外层去重或没处理多众数场景,导致结果行数爆炸或随机取值不可靠。
- 内层子查询按
group_col和value_col分组计数,并用ROW_NUMBER() OVER (PARTITION BY group_col ORDER BY COUNT(*) DESC, value_col)排序——加value_col是为了保证排序确定性(避免仅靠 COUNT 时相同频次的行顺序不确定) - 外层用
WHERE rn = 1取每组最高频次项;若需返回所有并列众数,改用RANK()并过滤rn = 1 - 如果某组所有值频次相同(如每组只有 1 行),该方法仍能返回唯一值,符合众数定义
SELECT group_col, value_col AS mode_value
FROM (
SELECT group_col, value_col,
ROW_NUMBER() OVER (
PARTITION BY group_col
ORDER BY COUNT(*) DESC, value_col
) AS rn
FROM your_table
GROUP BY group_col, value_col
) ranked
WHERE rn = 1;
用 ARRAY_AGG(...) WITHIN GROUP 配合下标取众数(更简洁但有陷阱)
利用 ARRAY_AGG 的有序聚合能力,先按频次排序再取第一个元素。比嵌套子查询少一层,但要注意 ORDER BY 必须在 WITHIN GROUP 内,且排序依据必须来自聚合键本身。
容易踩的坑是误把 COUNT(*) 当作可排序字段直接写进 WITHIN GROUP——这是非法的,WITHIN GROUP 只接受表达式中出现的非聚合列或常量。
- 正确做法:先用子查询算好每个
(group_col, value_col)的频次,再在外层用ARRAY_AGG(value_col ORDER BY freq DESC, value_col LIMIT 1) - PostgreSQL 15 不支持
LIMIT在ARRAY_AGG中,所以必须用子查询生成带freq列的结果集 - 这个方法比
ROW_NUMBER版稍慢,因为要构造数组再取索引,但逻辑更贴近“取最高频值”的直觉
NULL 值和数据类型对众数结果的影响
GROUP BY 默认忽略 NULL,所以如果 value_col 含 NULL,它们不会参与频次统计,也不会成为众数。若业务上需把 NULL 当作有效取值,得显式处理:
- 用
COALESCE(value_col, 'NULL_PLACEHOLDER')转换,但要注意类型匹配(比如INT字段不能直接COALESCE成字符串) - 或者在分组时写
GROUP BY group_col, (value_col IS NOT NULL), value_col,把NULL单独归为一类 - 字符类型要注意大小写和空格——
'A'和'a'在默认 collation 下是不同值,可能被误判为两个众数
真正麻烦的是多众数场景:业务是否接受任选其一?还是必须报错或返回数组?PostgreSQL 15 没有原生支持,得靠应用层判断 COUNT(*) 是否大于 1 来决定后续逻辑。










