ntile是sql窗口函数,用于将有序数据按指定数量均匀分桶并返回桶号;必须配合order by使用,支持partition by分区计算,分配时小编号桶优先多分一行,仅编号不提供分位数值。

NTILE 不是计算真实分位数值(比如 0.25 分位点对应的 salary 值),而是把行按顺序“切块编号”——它返回的是桶号,不是分位数本身。
NTILE(n) 必须带 ORDER BY,否则结果不可靠
ORDER BY 是 NTILE 的强制依赖项。没有它,数据库无法确定哪行该进哪个桶,MySQL、PostgreSQL、Oracle 等都会报错或返回随机分配结果。
- 错误写法:
NTILE(4) OVER ()—— 缺少ORDER BY,语法不合法 - 危险写法:
NTILE(4) OVER (PARTITION BY deptno)—— 仍缺ORDER BY,分区后各行顺序未定义 - 正确写法:
NTILE(4) OVER (PARTITION BY deptno ORDER BY salary DESC)
注意:排序方向直接影响分档含义。用 DESC 时,NTILE=1 表示高薪档;用 ASC 则相反。
桶数 n 不能为 0 或负数,且必须是整数常量
NTILE 的第一个参数 n 必须是正整数常量(如 4、10),不能是列名、变量或表达式(如 NTILE(dept_size) 或 NTILE(ROUND(3.7)))。
- 支持范围通常是
1到2^63-1,但实际建议控制在100以内,避免桶太多导致每桶仅 1 行 - 若
n > 总行数(例如NTILE(10) OVER (ORDER BY x)作用于 7 行),前 7 个桶各得 1 行,8–10 桶无数据,对应行的NTILE值仍是1–7 - MySQL 8.0+ 和 PostgreSQL 11+ 支持,但 MySQL 5.7 及更早版本不支持窗口函数,会报错
FUNCTION xxx.NTILE does not exist
分区(PARTITION BY)决定分桶边界,不加则全表一桶
是否加 PARTITION BY 直接改变业务语义:
- 不加:
NTILE(4) OVER (ORDER BY amount)—— 全表按金额从小到大四等分,跨部门混排 - 加分区:
NTILE(4) OVER (PARTITION BY region ORDER BY amount)—— 每个region内各自四等分,A 区第 1 桶 ≠ B 区第 1 桶 - 常见误用:在 RFM 分析中对用户整体跑
NTILE(5),却忘了按user_id聚合后再分桶,导致原始订单行直接被分档,失去用户粒度
特别注意:PARTITION BY 后的数据分布会影响桶内行数。例如某部门只有 2 人,NTILE(4) 仍只产生 1 和 2 两个值,不会补出 3、4。
NTILE 分配不均时,小编号桶优先多分一行
当行数 N 不能被 n 整除时,NTILE 采用“前余后匀”策略:前 N % n 个桶各多 1 行,其余桶少 1 行。
- 11 行分 4 桶 → 桶大小为
[3, 3, 3, 2],对应NTILE值为1,1,1,2,2,2,3,3,3,4,4 - 这不是四分位数(quartile)的统计定义,也不代表每个桶覆盖 25% 的数值区间——只是行数近似均分
- 若需真实分位数值(如中位数),应改用
PERCENTILE_CONT(0.5)或APPROX_PERCENTILE(取决于数据库支持)
真正容易被忽略的一点:NTILE 给的是**序号标签**,不是区间边界。想导出“第 1 桶的 salary 范围”,必须额外聚合:SELECT MIN(salary), MAX(salary), ntile FROM (...) GROUP BY ntile。










