Clasificar filas y calcular totales acumulados con funciones de ventana
Usa funciones de ventana SQL para clasificar filas, calcular totales acumulados y comparar valores dentro de particiones sin self-joins.
Nota para desarrolladores hispanohablantes: Esta guía incluye ejemplos y convenciones de nomenclatura adaptadas a equipos que trabajan en español. Cuando existen diferencias significativas en terminología técnica entre el inglés y el español, se indican explícitamente para facilitar la comunicación en equipos multiculturales.
Visión General
Las funciones de ventana son una de las características más potentes de SQL. Permiten calcular valores a través de un conjunto de filas relacionadas con la fila actual sin colapsar el resultado como GROUP BY. El ranking, totales acumulados y promedios móviles se vuelven directos, y a menudo reemplazan self-joins lentos o loops en la capa de aplicación.
Cuándo Usar
Usa este recurso cuando:
- Necesites clasificar filas dentro de grupos (top-N por categoría).
- Quieras totales acumulados o promedios móviles sin subconsultas.
- Estés construyendo tablas de clasificación, reportes de ventas o paginación con empates.
- Necesites comparar cada fila con la anterior o siguiente.
Solución
Ranking y totales acumulados
SELECT
department,
employee,
salary,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS row_num,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_num,
SUM(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS running_total,
LAG(salary) OVER (PARTITION BY department ORDER BY salary DESC) AS prev_salary
FROM employees;
Explicación
ROW_NUMBER() asigna un número único a cada fila de la partición. RANK() da el mismo ranking a empates, dejando huecos. SUM() OVER calcula un total acumulado porque el marco de ventana por defecto abarca filas desde el inicio de la partición hasta la fila actual. LAG() devuelve el valor de la fila anterior, útil para deltas. La cláusula PARTITION BY reinicia cálculos por departamento, y ORDER BY controla la secuencia dentro de la partición.
Variantes
| Función | Caso de uso | Comportamiento |
|---|---|---|
| ROW_NUMBER | Ranking único | Sin huecos, sin empates |
| RANK | Ranking con empates | Huecos tras empates |
| DENSE_RANK | Ranking con empates | Sin huecos |
| SUM OVER | Totales acumulados | Acumulativo dentro de partición |
| LAG/LEAD | Comparar filas adyacentes | Offset de N filas |
Mejores Prácticas
- Indexa columnas de partición y orden. La base de datos aún necesita ordenar; los índices ayudan.
- Usa ROW_NUMBER para top-N cuando los empates no importan. Usa RANK o DENSE_RANK cuando los empates importan.
- Los marcos de ventana importan. Agrega
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROWexplícitamente para claridad. - Evita anidar funciones de ventana. Algunas bases de datos no permiten
SUM() OVER (ORDER BY ROW_NUMBER() OVER...). - Materializa reportes complejos. Para dashboards, pre-agrega resultados de ventana en una tabla resumen.
Errores Comunes
- Olvidar PARTITION BY. Sin ella, la ventana cubre toda la tabla, mezclando departamentos.
- Confundir RANK y ROW_NUMBER. Los empates pueden producir resultados inesperados si eliges la función incorrecta.
- Usar funciones de ventana en WHERE. La mayoría de bases de datos requieren una subconsulta porque las ventanas se ejecutan después del filtrado.
- Dirección de ORDER BY incorrecta. El orden descendente es común para rankings; ascendente para totales acumulados.
- Ignorar NULLs en el ordenamiento. Los NULLs se ordenan primero o último según la base de datos; sé explícito con
NULLS FIRST/NULLS LAST.
Preguntas Frecuentes
P: ¿Cuál es la diferencia entre RANK y DENSE_RANK? R: RANK deja huecos tras empates (1, 1, 3). DENSE_RANK no (1, 1, 2).
P: ¿Puedo usar funciones de ventana con GROUP BY? R: Las ventanas se ejecutan después de GROUP BY, así que puedes combinarlas, pero debes agregar antes de aplicar la ventana.
P: ¿Cómo obtengo las top 3 filas por grupo?
R: Usa ROW_NUMBER() OVER (PARTITION BY group ORDER BY value DESC) y filtra WHERE row_num <= 3 en una consulta externa.
Recursos Relacionados
SQL Window Functions — Complete Guide
A practical guide to SQL window functions: ROW_NUMBER, RANK, DENSE_RANK, LEAD, LAG, SUM, AVG over partitions, and real-world analytics use cases.
RecipeFind and Remove Duplicate Rows in SQL
Detect duplicate records in SQL tables using GROUP BY and HAVING, then remove them safely while keeping the canonical row.
RecipeTraverse Hierarchical Data with Recursive CTEs
Query tree-like or graph-like structures in SQL using recursive common table expressions to walk parent-child relationships.
DocDatabase Schema Documentation Template
A template for documenting database schemas with entity relationships, field definitions, and migration history.
GuideFull-Text Search — Implement Search That Actually Works
A practical guide to full-text search: PostgreSQL tsvector, Elasticsearch indexing, query design, relevance tuning, and building search that users trust with autocomplete, faceting, and typo tolerance.