SQL无标准MEDIAN函数,主流引擎需用percentile_cont(0.5) WITHIN GROUP (ORDER BY ...)(PostgreSQL 14+)、自定义窗口逻辑(MySQL 8.0+/SQL Server)或应用层处理,并注意NULL过滤、排序稳定性和精度要求。

SQL里没有标准MEDIAN函数,别硬找
绝大多数主流SQL引擎(MySQL、PostgreSQL旧版、SQL Server)根本不提供内置MEDIAN函数。你执行SELECT MEDIAN(price) FROM sales,大概率会直接报错function does not exist或invalid function name。这不是你写错了,是它真没这个函数。
PostgreSQL 14+ 可用percentile_cont,但要注意语法细节
PostgreSQL从14开始支持percentile_cont计算连续分布的分位数,中位数就是第50百分位,但它不是MEDIAN(),也不能直接GROUP BY后套用——必须配合OVER()或子查询。
-
percentile_cont(0.5) WITHIN GROUP (ORDER BY amount)是正确写法,WITHIN GROUP不可省略,且必须带ORDER BY - 想按
category分组求中位数?得用子查询或GROUP BY+ 窗口函数组合,例如:SELECT category, percentile_cont(0.5) WITHIN GROUP (ORDER BY amount) AS median_amount FROM sales GROUP BY category;
- 注意:该函数返回
DOUBLE PRECISION,若原始字段是INTEGER,结果可能带小数(比如两个中间值平均后为4.5),和严格整数中位数语义不完全等价
MySQL和SQL Server得自己拼,别信“一条语句搞定”的方案
网上很多“用ROW_NUMBER() + COUNT()算中位数”的写法,在MySQL 8.0+或SQL Server里看似可行,但实际容易在边界情况翻车:
- 数据行数为偶数时,是否取上下两个中间值的平均?有些实现只取其中一个,逻辑错误
- 相同值密集出现(比如一堆0)时,
ROW_NUMBER()生成的序号无法保证稳定排序,除非显式加ORDER BY id等唯一键 - MySQL早期版本不支持窗口函数,强行用变量模拟
@row := @row + 1在并发查询下会出错 - 真实建议:对中小数据量,用应用层排序后取索引;对大数据量,考虑建临时序列表或改用
APPROX_PERCENTILE(如BigQuery/Redshift支持)
别忽略NULL和重复值对中位数的影响
中位数定义依赖有序序列,而NULL默认被ORDER BY排在最前或最后(行为因数据库而异),直接参与计算会导致结果偏移。重复值本身没问题,但若字段有大量NULL,percentile_cont或自定义逻辑可能把它们计入长度统计,导致中位位置算错。
- 务必先清理:
WHERE amount IS NOT NULL,别指望聚合函数自动过滤 - 验证时拿5行数据手动排个序,对照SQL输出看是不是第3个值;再试6行,确认是否真取了第3、4个的平均
- 如果业务允许近似结果,某些引擎(如Presto、Trino)提供
approx_percentile,性能好但不精确——这点常被忽略

















