因为sql标准未定义median()函数,mysql、postgresql 13及更早版、sql server 2019及之前版本均不支持,执行select median(salary) from employees会直接报错“function median() does not exist”。

为什么执行 MEDIAN() 会直接报错?
因为 SQL 标准压根没定义 MEDIAN() 这个聚合函数。你写的 SELECT MEDIAN(salary) FROM employees 在 MySQL、PostgreSQL 13 及更早版、SQL Server 2019 及之前版本里,一定会触发类似 ERROR: function median() does not exist 的错误——不是语法写错,是函数根本不存在。
PERCENTILE_CONT(0.5) 和 MEDIAN() 是一回事吗?
语义上接近,但实现和行为差异很大:
-
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x)是 PostgreSQL 9.4+、SQL Server 2022+、Oracle 等支持的标准化写法,它返回连续插值中位数(比如 [1,2,3,4] 返回 2.5),必须带WITHIN GROUP子句,不能加OVER() -
MEDIAN()仅在少数系统原生存在:Databricks SQL(11.3+)、Oracle(单列非分组)、Redshift(部分版本);但 Oracle 的MEDIAN()不支持GROUP BY,Redshift 的实际行为可能跳过 NULL 而不声明 - 两者对 NULL 的处理看似一致(默认忽略),但排序时若没显式写
NULLS LAST,MySQL 和 PostgreSQL 可能将 NULL 排最前,导致中位位置计算偏移
为什么分组中位数不能靠 MEDIAN() OVER (PARTITION BY ...)?
主流数据库全都不支持这种语法:
- PostgreSQL:
MEDIAN()不是窗口函数,MEDIAN() OVER ()会报错;PERCENTILE_CONT(0.5)本身也不是窗口函数,只能用于聚合或子查询 - MySQL 8.0+:无
MEDIAN(),也无PERCENTILE_CONT;必须用ROW_NUMBER()+COUNT() OVER (PARTITION BY dept)手动定位中间行号 - SQL Server 2022 以前:只能手写逻辑;2022+ 支持
PERCENTILE_CONT(0.5) OVER (PARTITION BY dept ORDER BY salary),但需注意ORDER BY必须存在且稳定(建议加id防并列)
真正跨库可用的中位数写法长什么样?
唯一可靠、可读、兼容 MySQL/PG/SQL Server 的方案,是基于行号的手动定位:
SELECT dept, AVG(salary) AS median_salary
FROM (
SELECT dept, salary,
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary, id) AS rn,
COUNT(*) OVER (PARTITION BY dept) AS cnt
FROM employees
WHERE salary IS NOT NULL
) t
WHERE rn IN (FLOOR((cnt + 1) / 2), CEIL((cnt + 1) / 2))
GROUP BY dept;
关键点:
-
ORDER BY salary, id防止相同薪资导致ROW_NUMBER()排序不稳定 -
WHERE salary IS NOT NULL必须显式过滤,不能依赖函数自动跳过 -
FLOOR和CEIL同时取,才能正确覆盖奇偶两种情况(3 行取第 2;4 行取第 2、3) - 大表务必在
(dept, salary, id)上建复合索引,否则ORDER BY会全表排序
别指望一条函数调用解决所有问题——中位数的语义依赖排序与位置,而各数据库对“排序稳定性”“NULL 位置”“窗口 vs 聚合”的实现分歧,比你想象中更深。











