Contenido de esta guía
Respuesta rápida
Con una partición de N filas, PERCENT_RANK() usa la idea (RANK - 1) / (N - 1). Por eso la primera posición vale 0 y, salvo la partición de una sola fila, la última puede llegar a 1. CUME_DIST() calcula la proporción de filas cuyo valor es menor o igual al valor actual; con empates, todas las filas del mismo grupo comparten la distribución acumulada del final del grupo.
Ejemplo con empates
WITH puntuaciones(nombre, puntos) AS (
VALUES ('Ana', 10), ('Bruno', 20), ('Celia', 20), ('Diego', 40)
)
SELECT
nombre,
puntos,
ROUND(PERCENT_RANK() OVER (ORDER BY puntos), 3) AS percent_rank,
ROUND(CUME_DIST() OVER (ORDER BY puntos), 3) AS cume_dist
FROM puntuaciones
ORDER BY puntos, nombre;| nombre | puntos | percent_rank | cume_dist |
|---|---|---|---|
| Ana | 10 | 0.0 | 0.25 |
| Bruno | 20 | 0.333 | 0.75 |
| Celia | 20 | 0.333 | 0.75 |
| Diego | 40 | 1.0 | 1.0 |
Bruno y Celia son pares porque tienen el mismo valor de orden. Comparten RANK(), por lo que también comparten PERCENT_RANK(). En CUME_DIST(), el grupo de 20 llega hasta la tercera de cuatro filas: 3/4 = 0,75.
Diferencia conceptual
| Función | Pregunta | Con empates |
|---|---|---|
PERCENT_RANK() | ¿Qué rango relativo ocupa este grupo de pares? | Usa el rango inicial del grupo. |
CUME_DIST() | ¿Qué proporción de filas queda por debajo o empatada? | Usa el final del grupo de pares. |
NTILE(4) | ¿En qué grupo de cuatro cae esta fila? | Busca grupos de tamaño equilibrado y puede separar empates. |
PARTITION BY reinicia el cálculo por grupo
Si comparas empleados dentro de cada departamento o productos dentro de cada categoría, añade PARTITION BY. Cada partición obtiene su propio total de filas y sus propios valores relativos.
WITH productos(categoria, nombre, precio) AS (
VALUES
('A', 'A1', 10), ('A', 'A2', 20), ('A', 'A3', 30),
('B', 'B1', 5), ('B', 'B2', 5), ('B', 'B3', 25)
)
SELECT
categoria,
nombre,
precio,
PERCENT_RANK() OVER (
PARTITION BY categoria
ORDER BY precio
) AS posicion_relativa,
CUME_DIST() OVER (
PARTITION BY categoria
ORDER BY precio
) AS distribucion_acumulada
FROM productos
ORDER BY categoria, precio, nombre;No son el percentil del valor ni la mediana
Estas funciones describen la posición de una fila observada. No calculan el valor que corresponde al percentil 50, 90 o 95. Para obtener un valor percentil algunos motores ofrecen funciones como PERCENTILE_CONT o PERCENTILE_DISC, con sintaxis y disponibilidad propias.
Modelo mental: PERCENT_RANK parte del puesto; CUME_DIST parte de cuántas filas ya quedan cubiertas por el valor actual.
Compatibilidad entre motores
PostgreSQL, SQLite, MySQL 8.4 y SQL Server documentan PERCENT_RANK() y CUME_DIST() como funciones de ventana. Requieren un orden para que la posición tenga significado. Los detalles de tipo devuelto y tratamiento específico de NULL pueden variar, así que no extrapoles un orden de nulos entre motores sin declararlo.
Práctica: posición de precios
Calcula rango relativo y distribución acumulada
Usa los cuatro precios siguientes y devuelve ambos indicadores ordenados de menor a mayor.
OVER (ORDER BY ...).GROUP BY.Solución razonada
WITH precios(valor) AS (
VALUES (10), (20), (20), (40)
)
SELECT
valor,
PERCENT_RANK() OVER (ORDER BY valor) AS percent_rank,
CUME_DIST() OVER (ORDER BY valor) AS cume_dist
FROM precios
ORDER BY valor;Las dos filas con valor 20 comparten ambos resultados. Ese comportamiento es la pista central para entender cómo las funciones tratan grupos de pares.
Qué debes recordar
PERCENT_RANK()deriva del rango relativo: empieza en 0.CUME_DIST()mide la fracción acumulada: su mínimo es mayor que 0 en una partición no vacía.- Los empates comparten resultado, pero cada función los interpreta desde un extremo distinto del grupo.
PARTITION BYreinicia el cálculo por grupo.- No confundas estas funciones con funciones que devuelven el valor de un percentil.