MySQL 8.0.13+需用PERCENTILE_CONT(0.5) OVER(PARTITION BY dept ORDER BY salary)计算分组中位数,必须带ORDER BY且不可与GROUP BY混用;PostgreSQL则支持更简洁的PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY salary)配合GROUP BY。

MySQL 8.0+ 直接用 PERCENTILE_CONT 计算分组中位数
MySQL 8.0.13 起支持窗口函数 PERCENTILE_CONT,它是计算中位数最接近标准定义的方式——返回指定百分位的连续插值结果。对中位数来说,就是 PERCENTILE_CONT(0.5)。
关键点:它必须配合 OVER(PARTITION BY ... ORDER BY ...) 使用,且 ORDER BY 子句不可省略,否则报错 Window 'w' with function PERCENTILE_CONT requires an ORDER BY clause。
- 只在分组内排序,不影响最终输出行数(每行都带本组中位数)
- 若需每个分组只出一行结果,得套一层
GROUP BY+MAX()或MIN()(因为同一组所有行的PERCENTILE_CONT值相同) - 注意:该函数返回
DECIMAL类型,若原始列为INT,结果可能带小数(如 [1,2,3,4] → 2.5)
SELECT dept, MAX(PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) OVER (PARTITION BY dept)) AS median_salary FROM employees GROUP BY dept;
PostgreSQL 用 PERCENTILE_CONT 更简洁
PostgreSQL 的 PERCENTILE_CONT 是聚合函数,直接写在 SELECT 中即可,无需窗口语法,也不强制要求子查询。
但要注意:它必须搭配 GROUP BY,且 ORDER BY 写在 WITHIN GROUP 里,不是外面的 ORDER BY。
- 错误写法:
PERCENTILE_CONT(0.5) OVER (PARTITION BY dept ORDER BY salary)—— PostgreSQL 不支持这种窗口用法 - 正确写法:
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary)必须出现在聚合上下文中 - 若字段含
NULL,默认被忽略(和AVG行为一致)
SELECT dept, PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary FROM employees GROUP BY dept;
SQLite 和老版本 MySQL 只能手写中位数逻辑
这些环境不支持 PERCENTILE_CONT,得靠行号模拟:先按组排序并编号,再找中间位置的值。核心难点是区分奇偶长度,以及处理重复值时是否允许取两个中间值的平均。
常见翻车点:
- 用
ROW_NUMBER()而不是RANK()—— 后者遇重复值会跳号,导致中位位置偏移 - 没过滤掉
NULL就排序,NULL在 SQLite 中排最前,在 MySQL 中排最后,行为不一致 - 误把
(COUNT(*) + 1) / 2当成唯一中位索引 —— 偶数长度时需要取第 n/2 和 n/2+1 两行的平均
一个较稳的 SQLite 写法(兼容性高,不依赖 CTE):
SELECT dept, AVG(salary) AS median_salary
FROM (
SELECT dept, salary,
(SELECT COUNT(*) FROM employees e2 WHERE e2.dept = e1.dept AND e2.salary = e1.salary) AS rank_desc
FROM employees e1
WHERE salary IS NOT NULL
)
WHERE rank_asc IN (rank_desc, rank_desc - 1, rank_desc + 1)
GROUP BY dept;
为什么不用 MEDIAN() 函数?
除了 Oracle(MEDIAN() 是聚合函数)和某些 OLAP 引擎,主流 SQL 方言基本不提供原生 MEDIAN()。MySQL 在 8.0 前完全缺失,PostgreSQL 明确不打算加(官方文档说“PERCENTILE_CONT 已足够”),SQLite 社区 PR 多次被拒。
所以别搜 MEDIAN(salary) —— 99% 情况下会报错 no such function: MEDIAN。真正要盯住的是 PERCENTILE_CONT 的语法细节,尤其是 WITHIN GROUP 和窗口 OVER 的适用场景差异。
跨数据库移植时,最易忽略的是 NULL 处理和排序稳定性;哪怕同一条语句,在 MySQL 和 PostgreSQL 里跑,ORDER BY 遇到相等值时的默认行为都可能不同。










