SQL analítico · funciones de ventana

PERCENT_RANK y CUME_DIST en SQL: posición relativa

PERCENT_RANK() mide el rango relativo de una fila; CUME_DIST() mide qué fracción de la partición está por debajo o empatada con ella. Ambas devuelven valores entre 0 y 1, pero reaccionan de forma distinta a los empates.

Lectura: 6–8 minVentanas y empatesPráctica con pistas
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

Comparar las dos funciones
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;
Resultado comprobado en SQLite 3.46.1
nombrepuntospercent_rankcume_dist
Ana100.00.25
Bruno200.3330.75
Celia200.3330.75
Diego401.01.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ónPreguntaCon 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.

Posición dentro de cada categoría
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

Intermedia · ventanas

Calcula rango relativo y distribución acumulada

Usa los cuatro precios siguientes y devuelve ambos indicadores ordenados de menor a mayor.

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 BY reinicia el cálculo por grupo.
  • No confundas estas funciones con funciones que devuelven el valor de un percentil.

Conceptos relacionados

Fuentes técnicas consultadas