postgresql不支持内置mode()函数,需用row_number()或mode() within group(14+)实现单众数,或用窗口函数max(count(*))获取全部并列众数,null值需显式处理。

PostgreSQL 本身没有内置 MODE() 聚合函数
直接写 SELECT MODE(x) FROM t GROUP BY y 会报错:ERROR: function mode(integer) does not exist。PostgreSQL 直到 14 版本仍未原生支持 MODE(),不像 Oracle 或 SQL Server 那样开箱即用。想求众数,得自己构造逻辑——核心思路是:先按分组和值计数,再取每组中频次最高的那个(或多个)值。
用 ROW_NUMBER() + GROUP BY 实现单众数(每组只返回一个最频繁值)
适用于「每组只要一个代表值」的场景,比如统计每个部门最常见的职级。关键在于对每组内各值的出现次数降序排序,取 ROW_NUMBER() = 1 的那条记录:
SELECT dept, role
FROM (
SELECT dept, role, COUNT(*) AS cnt,
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY COUNT(*) DESC, role) AS rn
FROM employees
GROUP BY dept, role
) ranked
WHERE rn = 1;
注意这里 ORDER BY COUNT(*) DESC, role 中加了 role 是为了保证排序确定性(避免因相同频次导致 rn 非预期波动);如果允许任意一个众数,可只写 COUNT(*) DESC,但结果可能不一致。
用 ARRAY_AGG() + MODE() WITHIN GROUP(仅限 PostgreSQL 14+)
PostgreSQL 14 引入了有序聚合语法 MODE() WITHIN GROUP (ORDER BY ...),但它**不是独立函数**,必须配合 WITHIN GROUP 子句使用,且只接受单一排序字段:
-
MODE() WITHIN GROUP (ORDER BY x)→ 返回该组中x出现次数最多的单个值(存在并列时返回排序靠前的那个) - 不能写成
MODE(x)或MODE() OVER (...) - 不支持多列联合众数(如「同时按 region 和 category 分组求 product_name 众数」需先
GROUP BY region, category再套一层)
示例(14+):
SELECT department,
MODE() WITHIN GROUP (ORDER BY job_title) AS most_common_title
FROM employees
GROUP BY department;
处理并列众数(返回所有最高频次的值)
当一组中有多个值并列最高频次(比如 A/B 各出现 5 次,C 出现 3 次),上面两种方法都只返回一个。要返回全部,得用窗口函数比对最大频次:
SELECT department, job_title
FROM (
SELECT department, job_title, COUNT(*) AS cnt,
MAX(COUNT(*)) OVER (PARTITION BY department) AS max_cnt
FROM employees
GROUP BY department, job_title
) t
WHERE cnt = max_cnt;
这个写法稳定兼容所有 PostgreSQL 版本,但要注意:如果某组所有值频次都为 1,它会返回全部值——这是正确行为(全为众数),不是 bug。若业务上需要排除「无显著众数」的情况,得额外加 HAVING COUNT(*) > 1 过滤。
真正麻烦的是 NULL 值参与统计:默认 COUNT(*) 不计 NULL,但 COUNT(col) 也不计 NULL;如果字段本身含 NULL 且你想把它当作一个有效取值来统计频次,得显式写 GROUP BY COALESCE(col, 'NULL_PLACEHOLDER') 或用 GROUPING SETS 单独处理,否则 NULL 会被直接忽略。











