PERCENTILE_DISC返回排序后实际存在的值,PERCENTILE_CONT则线性插值得到理论值;前者结果必在原始数据中,后者可能为不存在的中间值。
PERCENTILE_DISC 返回排序后实际存在的某个值,不是插值结果。它按指定百分位数位置向下取整,找最接近且不大于该位置的现有行——所以结果一定来自原始数据集。而 PERCENTILE_CONT 会线性插值,可能返回原始数据里根本不存在的数值。
PERCENTILE_DISC 要求 ORDER BY 子句,且只支持单列排序(不能写 ORDER BY col1, col2)OVER() 窗口函数使用,不能直接用于聚合上下文0.0 到 1.0 之间的常量或标量表达式,不支持列引用常见错误是漏掉 ORDER BY 或误用聚合方式。正确结构只有这一种:
SELECT DISTINCT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY salary) OVER() AS median_salaryFROM employees;
WITHIN GROUP (ORDER BY ...) 是强制语法,括号内只能是单列、确定排序方向(默认 ASC)OVER() 不能为空,但可以不带分区或排序(即全局计算);如果加了 PARTITION BY dept,就按部门分别取中位数PERCENTILE_DISC(0.25)、PERCENTILE_DISC(0.5)、PERCENTILE_DISC(0.75)
ORDER BY 列全部为空,PERCENTILE_DISC 必返回 NULL(不像某些聚合函数会跳过 NULL)1.01 或 -0.1 会报错,不是静默转成边界值function does not exist 错误SELECT dept, PERCENTILE_DISC(0.5) WITHIN GROUP... 但没加 OVER(PARTITION BY dept) —— 这会导致“窗口函数不能出现在 GROUP BY 上下文中”的错误PERCENTILE_DISC 对重复值和排序稳定性敏感。例如 salary 列有大量相同值(如 8000 出现 12 次),不同执行可能因隐式排序顺序差异选中不同行(尽管值一样,但底层 rowid 不同)。
ORDER BY salary, employee_id(注意:这违反单列限制,所以得改用 ORDER BY salary + 0.0001 * employee_id 这类 trick,或提前用子查询生成稳定序号)ROW_NUMBER() OVER (ORDER BY salary, employee_id) 手动编号,再按公式 FLOOR((n-1) * p) + 1 取第 k 行(n 是总行数,p 是百分位),这样完全可控PERCENTILE_CONT 反而更稳——它不依赖具体哪一行,只依赖两端值实际用的时候,别只盯着函数名,先确认你的数据库版本是否真支持,再看排序列有没有隐含的不确定性。很多线上问题,都是因为开发环境用 PostgreSQL 14 测试通过,上线到 SQL Server 2016 却发现不识别这个函数。