postgresql不支持直接使用median()函数,必须用percentile_cont(0.5) within group (order by x)或percentile_disc(0.5) within group (order by x)替代,前者返回插值中位数,后者返回离散实际值。

PostgreSQL 怎么直接用 MEDIAN?
PostgreSQL 从 14 版本起才原生支持 MEDIAN 聚合函数,且仅限于 ORDER BY 子句配合使用,不是像 AVG 那样直接写 SELECT MEDIAN(x)。常见错误是查文档看到 “MEDIAN supported” 就直接用,结果报错 function median(double precision) does not exist。
- 必须写成
SELECT PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x)(推荐,返回连续插值中位数) - 或
PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY x)(返回实际存在的中间值,数据量为偶数时取较小的那个) -
PERCENTILE_CONT在小数位置会线性插值,比如 [1,3] 返回 2.0;PERCENTILE_DISC则返回 1 或 3(取决于排序和实现,PostgreSQL 中返回第一个满足条件的值,即 1)
MySQL 没有 MEDIAN 函数,怎么手写?
MySQL 直到 8.0.32 仍不提供内置中位数聚合函数,强行用窗口函数模拟时容易在分组场景出错(比如对每个 category 算中位数),常见翻车点是没处理好 ROW_NUMBER() 和总行数奇偶判断。
- 先算总数:
SELECT COUNT(*) FROM t,再用子查询或 CTE 获取每组的行号与中位位置 - 更稳的做法是用两层嵌套:
(SELECT AVG(val) FROM (SELECT val, ROW_NUMBER() OVER (ORDER BY val) AS rn, COUNT(*) OVER() AS cnt FROM t) t2 WHERE rn IN (FLOOR((cnt+1)/2), CEIL((cnt+1)/2))) - 注意:如果表很大,
COUNT(*) OVER()会触发全表扫描 + 排序,性能比AVG差一个数量级;线上慎用于高频查询
SQL Server 的 PERCENTILE_CONT 为什么返回 NULL?
SQL Server 支持 PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY x) OVER (PARTITION BY y),但很多人忽略两个硬性前提:
- 输入列
x不能为NULL,否则整行被跳过,最终结果可能为空 → 查前先加WHERE x IS NOT NULL -
OVER子句必须存在(哪怕不分组也要写OVER ()),否则报错Incorrect syntax near 'ORDER' - 分组计算时,若某组全为 NULL,则该组结果为 NULL;想统一兜底可套一层
COALESCE(..., 0),但得确认业务是否接受这种默认值
SQLite 怎么绕过没有聚合中位数的限制?
SQLite 连 PERCENTILE_CONT 都不支持,也没有窗口函数(3.25+ 虽加了 ROW_NUMBER(),但不支持 OVER (ORDER BY ...) 在聚合上下文中使用),最简方案是靠子查询 + 自连接计数,但数据量稍大就卡死。
- 可行但慢的方法:
SELECT x FROM t t1 WHERE (SELECT COUNT(<em>) FROM t t2 WHERE t2.x ) FROM t)/2</em>(只适用于奇数行) - 实用建议:导出数据用 Python/awk 算中位数,或者升级到 SQLite 3.40+ 后用
json_group_array+ 外部脚本解析(不推荐生产环境依赖) - 真正在 SQLite 里跑中位数,基本等于承认“这个指标不适合在端侧实时算”
中位数不是所有数据库都当一等公民对待的聚合操作,尤其涉及分组、NULL 值、大数据量时,各厂实现逻辑差异比表面看起来大得多——别光看语法像,得盯住执行计划和结果精度。











