不能。PERCENT_RANK() 返回相对排名百分位(0到1),但无法保证50%位置对应真实数据点,尤其偶数行时需取两值平均,而它仅能标记最接近0.5的行,不能自动计算中位数。
PERCENT_RANK 能不能直接算中位数
不能。虽然
返回的是「相对排名百分位」(范围 0 到 1,首行固定为 0),但它不保证第 50% 位置一定对应一个真实数据点——尤其当行数为偶数时,真正的中位数可能落在两个值之间,而
最多只能标记出最靠近 0.5 的那行(或两行),无法自动取平均。它适合筛选“前 10%”这类场景,但不适合直接替代中位数逻辑。
用 PERCENT_RANK 模拟中位数的可行做法
如果你坚持用
(比如已有查询框架依赖该函数、或需同时输出分位信息),可以结合
和条件过滤逼近中位数:
先按目标列升序排序,对每行计算
找
最接近 0.5 的行:可用
,但注意 MySQL 8.0 不支持在窗口函数后直接嵌套聚合,得用 CTE 或派生表
更稳妥的做法是用两个子查询分别取「≤ 50% 分位的最大值」和「≥ 50% 分位的最小值」,再平均——但这已脱离
本意,实际等价于手写
方案
示例(简化版,仅返回一个近似中位数,非严格数学中位数):
为什么推荐改用 ROW_NUMBER + COUNT 更可靠
MySQL 8.0 原生中位数没内置函数,但用
和总行数能精确处理奇偶两种情况,且性能可控:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
给每行唯一序号(从 1 开始)
获取总行数
,中位数位置就是
(奇数)或
和
(偶数)
避免
在重复值多时产生的并列排名“挤占”问题(例如 5 行相同值,
全是 0,无法区分)
典型写法(兼容奇偶):
容易被忽略的边界情况
所有基于窗口函数的中位数方案都必须显式处理空值和全 NULL 列:
默认把
排在最前(MySQL 8.0),若业务要求忽略
,必须加
如果表为空,
返回 0,
,会导致
查不到任何行,结果为
—— 这是正确行为,但需确认上层是否接受
重复值不影响
序号分配,但会影响业务语义上的“中间位置”,这点比
更透明可预期
真正要用
算中位数,本质是在用错工具;它存在的意义是描述分布形状,不是定位中心点。
PERCENT_RANK()PERCENT_RANK()PERCENT_RANK()ORDER BYPERCENT_RANK() OVER (ORDER BY value)PERCENT_RANKABS(PERCENT_RANK() - 0.5) = (SELECT MIN(ABS(PERCENT_RANK() - 0.5)) FROM ...)PERCENT_RANKROW_NUMBERWITH ranked AS (
SELECT value, PERCENT_RANK() OVER (ORDER BY value) AS pr
FROM t
)
SELECT AVG(value)
FROM ranked
WHERE pr IN (
(SELECT MAX(pr) FROM ranked WHERE pr <= 0.5),
(SELECT MIN(pr) FROM ranked WHERE pr >= 0.5)
);ROW_NUMBER()ROW_NUMBER() OVER (ORDER BY value)COUNT(*) OVER()n(n+1)/2n/2n/2+1PERCENT_RANKPERCENT_RANKWITH numbered AS (
SELECT value, ROW_NUMBER() OVER (ORDER BY value) AS rn, COUNT(*) OVER() AS cnt
FROM t
)
SELECT AVG(value)
FROM numbered
WHERE rn IN (FLOOR((cnt + 1) / 2), CEIL((cnt + 1) / 2));ORDER BY valueNULLNULLWHERE value IS NOT NULLCOUNT(*) OVER()FLOOR((0+1)/2)=0rn IN (0,1)NULLROW_NUMBERPERCENT_RANKPERCENT_RANK