oracle中位数应使用percentile_cont(0.5) within group (order by ...),不可用over();需确保排序字段为数值型、null自动忽略但影响样本量,分组计算须匹配group by,且参数0.5必须为常量。

PERCENTILE_CONT(0.5) 是 Oracle 中计算中位数最直接、最标准的方式,它返回连续分布下的插值结果,语义准确,无需手写 ROW_NUMBER() 或变量模拟。
必须用 WITHIN GROUP (ORDER BY ...),不能用 OVER()
Oracle 支持聚合式写法,不支持窗口函数形式的 OVER (PARTITION BY ... ORDER BY ...) 用于中位数聚合(虽然语法上允许,但行为不符合直觉)。你真正需要的是:
-
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount)—— 这才是 Oracle 认可的、能直接出单值中位数的写法 - 误写成
PERCENTILE_CONT(0.5) OVER (ORDER BY amount)会报错:ORA-30498: missingWITHIN GROUPclause - 即便加了
PARTITION BY,也必须走WITHIN GROUP路径;想分组算,就配合GROUP BY
ORDER BY 字段必须是数值型,且 NULL 默认被忽略
Oracle 会自动跳过 NULL 值参与排序和插值,这点不用额外 WHERE amount IS NOT NULL —— 但要注意副作用:
- 如果某组数据里有大量
NULL,实际参与计算的行数变少,中位数可能意外偏移 - 排序字段若为
VARCHAR2(比如把金额转成字符串再排序),会导致字典序排序,PERCENTILE_CONT结果完全失真 - 推荐显式转换并校验类型:
TO_NUMBER(amount),或建索引前确认字段定义是NUMBER
按分组计算中位数时,GROUP BY 和 WITHIN GROUP 必须匹配
常见错误是混用普通列和聚合函数却不分组,导致 ORA-00979: not a GROUP BY expression。正确姿势是:
- 所有非聚合列都得出现在
GROUP BY中 -
WITHIN GROUP (ORDER BY ...)里的字段可以和GROUP BY不同,但必须是数值型 - 示例(按部门算薪资中位数):
SELECT dept_name,
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY salary) AS median_salary
FROM employees
GROUP BY dept_name;
- 别试图在同一个查询里既选
employee_name又用PERCENTILE_CONT而不GROUP BY employee_name——Oracle 会立刻拒绝
和 PERCENTILE_DISC(0.5) 的选择取决于业务定义
两者在 Oracle 中都可用,但语义不同,不是“精度高低”问题:
-
PERCENTILE_CONT(0.5)插值:数据[100, 200, 300, 400]→ 返回250.0 -
PERCENTILE_DISC(0.5)取实值:同样数据 → 返回200(第 2 个,即FLOOR((n+1)/2)位置) - 财务类指标(如客单价、ARPU)、需平滑统计的场景,优先用
CONT - 等级、评分、合规报告等要求“真实存在”的值,才换
DISC - 参数都必须是常量
0.5,不能是列、变量或表达式,否则报 ORA-00932
PERCENTILE_CONT 的实现非常稳定,但容易栽在语法细节上:少一个括号、错用 OVER、混写非分组列——这些都不是性能问题,而是直接报错或静默逻辑错误。真正要盯住的,是 WITHIN GROUP 结构是否完整、排序字段是否可信、分组维度是否对齐。











