能,oracle中median()可直接与group by联用,为每个分组返回一行精确中位数,空值自动忽略,偶数个值取中间两数平均;但select中不可混用非聚合列,否则报ora-00937。

Oracle里MEDIAN()直接配GROUP BY能用吗?
能,但只限于标准聚合场景——即每个分组返回一行结果。你写MEDIAN(sal) GROUP BY deptno完全合法,Oracle 会为每个 deptno 算出一个中位数值,结果行数等于分组数。
常见误解是认为它“不能和 GROUP BY 一起用”,其实错在混淆了「聚合函数」和「分析函数」的语义边界。只要不混用非聚合列(比如 SELECT deptno, ename, MEDIAN(sal) GROUP BY deptno 就会报 ORA-00937),就没问题。
- 空值自动跳过,无需
WHERE sal IS NOT NULL - 偶数个值时取中间两数平均,结果是精确值,不是估算
- 如果某组所有
sal都是 NULL,MEDIAN()返回 NULL —— 这不是 bug,是符合定义的行为
MEDIAN() OVER(PARTITION BY ...) 和 GROUP BY 有什么区别?
核心区别是输出行数不同:用 GROUP BY 是「压缩式」输出,每组一行;用 MEDIAN() OVER(PARTITION BY ...) 是「广播式」输出,原表有多少行,结果就有多少行,每行附带其所在分组的中位数。
例如对 emp 表按 deptno 分组:
-
SELECT deptno, MEDIAN(sal) FROM emp GROUP BY deptno→ 输出 3 行(假设 3 个部门) -
SELECT deptno, sal, MEDIAN(sal) OVER(PARTITION BY deptno) AS median_sal FROM emp→ 输出 14 行(原表行数),每行都带本部门中位数
注意:分析函数写法必须加 DISTINCT 或外层包装才能得到「每组一行」的结果,否则容易误以为“没去重”。
大数据量下,MEDIAN() 性能怎么样?
Oracle 的 MEDIAN() 底层做了优化,对单列聚合效率尚可,但有两个隐性成本容易被忽略:
- 它需要内部排序 —— 如果
sal列没索引,且分组内数据量大(比如某部门上百万员工),排序开销会明显上升 - 用
OVER(PARTITION BY ...)时,Oracle 可能为每个分区单独排序,比纯 GROUP BY 更耗资源 - 如果只是想查中位数本身,别顺手 SELECT *,避免把大字段拖进结果集加重 I/O
实测中,当单分组记录超 50 万,MEDIAN() 耗时可能翻倍;此时可考虑先抽样或加物化视图缓存。
为什么有时结果看起来“不对”?几个典型陷阱
不是函数错了,而是数据状态或写法触发了边缘逻辑:
- 分组内只有 1 行:正常返回该行值,但若该值是 NULL,结果就是 NULL —— 容易误判为“没算出来”
- 用了
ORDER BY在聚合查询里(如SELECT MEDIAN(sal) FROM emp ORDER BY deptno):ORDER BY 对单行结果无意义,还可能干扰执行计划 - 列类型是
VARCHAR2且含数字字符串:Oracle 会隐式转DOUBLE,但遇到 '12.3a' 这类非法格式会报 ORA-01722,需提前清洗 - 在 PL/SQL 块里调用
MEDIAN():它不能作为标量函数直接赋值给变量,必须走 SELECT INTO
最常被忽略的一点:MEDIAN() 永远只作用于当前查询可见的数据集 —— 它不感知事务未提交的更改,也不读取其他会话的临时表内容。











