percentile_cont(0.5)是标准sql中计算中位数最直接可靠的方式,基于线性插值:偶数行取中间两值平均,奇数行取正中原始值;必须配合over(partition by ... order by ...)或within group(order by ...)使用,不支持mysql/sqlite。

PERCENTILE_CONT(0.5) 是计算中位数最直接的方式
在支持窗口函数的数据库(如 PostgreSQL、Oracle、SQL Server 2012+、Snowflake、BigQuery)中,PERCENTILE_CONT(0.5) 是标准且可靠的中位数计算方法。它基于线性插值,在偶数个值时自动取中间两数的平均值,行为符合统计学定义。
关键点:必须配合 OVER() 窗口子句使用,且 ORDER BY 不可省略——否则结果未定义,多数引擎会报错或返回任意值。
常见错误现象:PERCENTILE_CONT(0.5) OVER ()(缺 ORDER BY)在 PostgreSQL 报错 ERROR: PERCENTILE_CONT requires an ORDER BY clause;在 SQL Server 可能静默返回错误结果。
-
PERCENTILE_CONT是连续分布函数,适用于数值型列;传入字符串或日期会类型不匹配 - 若需按组计算中位数,把分组字段加进
PARTITION BY,例如:PERCENTILE_CONT(0.5) OVER (PARTITION BY category ORDER BY amount) - 该函数返回
DOUBLE PRECISION或等效浮点类型,整数列结果可能带小数(如中位数是 5,返回 5.0),必要时用ROUND(..., 0)或显式::INTEGER转换
MySQL 和 SQLite 用户别硬套 PERCENTILE_CONT
MySQL 8.0.13+ 才支持 PERCENTILE_CONT,且仅限窗口函数形式(不能用于聚合上下文);SQLite 完全不支持。强行写会报错 FUNCTION xxx.PERCENTILE_CONT does not exist 或语法错误。
替代方案不是“改写函数”,而是换思路:
- MySQL 8.0+:可用
ROW_NUMBER()+ 分组计数,定位中间行索引,再用条件聚合取值(需两层子查询) - SQLite:依赖
(SELECT COUNT(*) FROM t) / 2和LIMIT 1 OFFSET ...拼接,但无法在单条语句中完成分组中位数,通常要借助 CTE 或应用层处理 - 如果只是临时查一组数据的中位数(非分组),PostgreSQL/BigQuery 可用
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x)—— 这是聚合形式,和窗口形式语法不同,别混用
GROUP BY + PERCENTILE_CONT 的典型写法和陷阱
想按 department 查每个部门薪资中位数?不能直接 GROUP BY department 后跟 PERCENTILE_CONT —— 因为它是窗口函数,不是聚合函数,和 GROUP BY 冲突。正确做法是用窗口函数算出每行对应的组中位数,再去重或聚合。
推荐写法(以 PostgreSQL 为例):
SELECT DISTINCT
department,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary)
OVER (PARTITION BY department) AS median_salary
FROM employees;
注意:WITHIN GROUP 形式是聚合函数,可与 GROUP BY 共存;而 OVER (PARTITION BY ...) 是窗口函数,不能出现在 SELECT 中同时有普通聚合(如 COUNT(*))除非全部用窗口或全部用聚合。
- 误写成
SELECT department, PERCENTILE_CONT(0.5) OVER (PARTITION BY department ORDER BY salary) FROM employees GROUP BY department→ 报错:窗口函数不能与 GROUP BY 混合使用 -
PERCENTILE_CONT对 NULL 值默认忽略,但如果ORDER BY列含大量 NULL,排序行为依赖数据库的 NULLS FIRST/LAST 默认策略(PostgreSQL 默认 NULLS LAST),可能影响中位数位置 - 大数据量下,
PERCENTILE_CONT性能取决于排序效率,确保ORDER BY字段上有索引(尤其是分组+排序复合场景)
为什么不用 PERCENTILE_DISC?它和中位数不是一回事
PERCENTILE_DISC(0.5) 返回的是“排序后位置最接近 50% 的实际存在的值”,不插值。当行数为偶数时,它只返回下中位数(即第 n/2 行),而非上下中位数平均值。
举例:序列 [1,2,3,4],PERCENTILE_CONT(0.5) 返回 2.5,PERCENTILE_DISC(0.5) 返回 2。后者不符合常规中位数定义,仅适合明确要求返回样本中真实值的场景(如排行榜名次)。
- 别因为名字里有 “PERCENTILE” 就默认它等于中位数——必须看后缀是
CONT还是DISC - 某些 BI 工具(如 Tableau)底层生成 SQL 时可能误用
DISC,导出数据对不上 Excel 的 MEDIAN() 函数结果,这时要检查生成的 SQL - 如果业务方坚持“中位数必须是原始数据中的一个”,才考虑
PERCENTILE_DISC,并书面确认该定义
PERCENTILE_CONT 的 SQL 换个库就可能结果偏移或报错。上线前务必在目标环境实测最小数据集。










