NTILE(n) es una funcion de ventana que divide un conjunto ordenado de filas en n cubos lo mas iguales posible en tamano y etiqueta cada fila con un numero de cubo de 1 a n. Es el caballo de batalla de cuartiles, deciles y cualquier cohorte de "igual numero de clientes por grupo".
El caso basico: cuartiles
Dividimos a los usuarios en cuatro grupos iguales por gasto total. ORDER BY ... DESC significa que el cubo 1 es el "top".
SELECT
u.id,
u.email,
SUM(o.amount) AS spent,
NTILE(4) OVER (ORDER BY SUM(o.amount) DESC) AS quartile
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE o.status = 'paid'
GROUP BY u.id, u.email;
La diferencia clave frente a RANK/ROW_NUMBER: NTILE mira el numero de filas, no los valores concretos. Diez filas con NTILE(4) producen cubos de tamano 3, 3, 2, 2 — la funcion coloca las filas por ti.
Como se reparte el resto
Cuando el numero de filas no se divide exacto entre n, las filas sobrantes van a los cubos de numero mas bajo. Para 10 filas y NTILE(4): el resto es 10 mod 4 = 2, asi que los dos primeros cubos reciben una fila extra cada uno.
- 10 filas,
NTILE(4) → 3, 3, 2, 2
- 11 filas,
NTILE(4) → 3, 3, 3, 2
- 7 filas,
NTILE(3) → 3, 2, 2
Trampa: cuando n es mayor que el numero de filas, algunos cubos nunca aparecen. Siete filas con NTILE(10) producen numeros del 1 al 7, y los cubos 8, 9, 10 quedan vacios. No supongas que todos los cubos existen.
Una segunda trampa: los valores iguales (empates) pueden caer en cubos distintos, porque se cuentan filas, no valores. Si el limite de una cohorte debe coincidir con un limite de valor, NTILE es la herramienta equivocada — usa WIDTH_BUCKET o un CASE manual.
PARTITION BY: deciles dentro de cada pais
PARTITION BY recalcula los cubos de forma independiente dentro de cada grupo. Abajo, deciles de gasto calculados por pais.
SELECT
u.country,
u.email,
SUM(o.amount) AS spent,
NTILE(10) OVER (
PARTITION BY u.country
ORDER BY SUM(o.amount) DESC
) AS decile
FROM users u
JOIN orders o ON o.user_id = u.id
GROUP BY u.country, u.email;
Cada pais obtiene su propia escalera del 1 al 10. La misma idea da deciles de salario por departamento en una sola consulta:
SELECT name, dept, salary,
NTILE(4) OVER (PARTITION BY dept ORDER BY salary DESC) AS pay_quartile
FROM employees;
NTILE frente a WIDTH_BUCKET
Es facil confundirlos, pero la logica es distinta:
NTILE(n) iguala el numero de filas entre los cubos. Cada cubo tiene mas o menos el mismo tamano, pero los rangos de valores fluctuan.
WIDTH_BUCKET(val, lo, hi, n) iguala el ancho del rango. Los cubos abarcan anchos de valor iguales, pero su numero de filas puede variar muchisimo.
SELECT id, amount,
WIDTH_BUCKET(amount, 0, 1000, 4) AS price_band
FROM orders;
Regla practica: "igual numero de clientes por grupo" → NTILE; "bandas de precio fijas" → WIDTH_BUCKET.
Compatibilidad
- PostgreSQL — soporta por completo tanto
NTILE como WIDTH_BUCKET.
- MySQL —
NTILE existe desde la 8.0; no hay WIDTH_BUCKET, asi que se emula con una expresion FLOOR(...).
- ClickHouse — no hay
NTILE nativo; usa intDiv(rowNumberInAllBlocks(), ...) o aritmetica sobre row_number().
Lo que hay que recordar: NTILE corta por filas, y el resto siempre se inclina hacia los cubos de numero mas bajo — eso es lo que hace que las cohortes por cuartiles sean honestas.
NTILE(n)es una funcion de ventana que divide un conjunto ordenado de filas enncubos lo mas iguales posible en tamano y etiqueta cada fila con un numero de cubo de1an. Es el caballo de batalla de cuartiles, deciles y cualquier cohorte de "igual numero de clientes por grupo".El caso basico: cuartiles
Dividimos a los usuarios en cuatro grupos iguales por gasto total.
ORDER BY ... DESCsignifica que el cubo1es el "top".SELECT u.id, u.email, SUM(o.amount) AS spent, NTILE(4) OVER (ORDER BY SUM(o.amount) DESC) AS quartile FROM users u JOIN orders o ON o.user_id = u.id WHERE o.status = 'paid' GROUP BY u.id, u.email;La diferencia clave frente a
RANK/ROW_NUMBER:NTILEmira el numero de filas, no los valores concretos. Diez filas conNTILE(4)producen cubos de tamano 3, 3, 2, 2 — la funcion coloca las filas por ti.Como se reparte el resto
Cuando el numero de filas no se divide exacto entre
n, las filas sobrantes van a los cubos de numero mas bajo. Para 10 filas yNTILE(4): el resto es10 mod 4 = 2, asi que los dos primeros cubos reciben una fila extra cada uno.NTILE(4)→ 3, 3, 2, 2NTILE(4)→ 3, 3, 3, 2NTILE(3)→ 3, 2, 2Una segunda trampa: los valores iguales (empates) pueden caer en cubos distintos, porque se cuentan filas, no valores. Si el limite de una cohorte debe coincidir con un limite de valor,
NTILEes la herramienta equivocada — usaWIDTH_BUCKETo unCASEmanual.PARTITION BY: deciles dentro de cada pais
PARTITION BYrecalcula los cubos de forma independiente dentro de cada grupo. Abajo, deciles de gasto calculados por pais.SELECT u.country, u.email, SUM(o.amount) AS spent, NTILE(10) OVER ( PARTITION BY u.country ORDER BY SUM(o.amount) DESC ) AS decile FROM users u JOIN orders o ON o.user_id = u.id GROUP BY u.country, u.email;Cada pais obtiene su propia escalera del 1 al 10. La misma idea da deciles de salario por departamento en una sola consulta:
SELECT name, dept, salary, NTILE(4) OVER (PARTITION BY dept ORDER BY salary DESC) AS pay_quartile FROM employees;NTILE frente a WIDTH_BUCKET
Es facil confundirlos, pero la logica es distinta:
NTILE(n)iguala el numero de filas entre los cubos. Cada cubo tiene mas o menos el mismo tamano, pero los rangos de valores fluctuan.WIDTH_BUCKET(val, lo, hi, n)iguala el ancho del rango. Los cubos abarcan anchos de valor iguales, pero su numero de filas puede variar muchisimo.-- Bandas de igual ANCHO: 0-250, 250-500, 500-750, 750-1000 SELECT id, amount, WIDTH_BUCKET(amount, 0, 1000, 4) AS price_band FROM orders;Regla practica: "igual numero de clientes por grupo" →
NTILE; "bandas de precio fijas" →WIDTH_BUCKET.Compatibilidad
NTILEcomoWIDTH_BUCKET.NTILEexiste desde la 8.0; no hayWIDTH_BUCKET, asi que se emula con una expresionFLOOR(...).NTILEnativo; usaintDiv(rowNumberInAllBlocks(), ...)o aritmetica sobrerow_number().Lo que hay que recordar:
NTILEcorta por filas, y el resto siempre se inclina hacia los cubos de numero mas bajo — eso es lo que hace que las cohortes por cuartiles sean honestas.