Avanzado

Funciones de Ventana: ROW_NUMBER, RANK, LEAD y LAG para un Análisis Superior

Publicado el 30 de Julio, 2025 Lectura de 11 min

Introducción: La Lente de Aumento para tus Datos

Hemos aprendido a agregar datos con GROUP BY y a combinar tablas con JOINs. Sin embargo, a menudo nos encontramos con preguntas que estas herramientas no pueden responder de forma sencilla, como clasificar empleados por salario dentro de cada departamento o calcular el crecimiento de ventas mes a mes.

GROUP BY es como una foto de equipo: resume la información y pierdes el detalle individual. Las funciones de ventana son como una foto de pasaporte individual con las estadísticas del equipo en el fondo: cada fila se mantiene, pero se enriquece con el contexto de su grupo.

En esta guía, abriremos la caja de herramientas de las funciones de ventana. Dominaremos las funciones de ranking como ROW_NUMBER, RANK y DENSE_RANK, y las funciones de desplazamiento como LEAD y LAG. Al final, serás capaz de realizar análisis complejos y sofisticados que antes parecían requerir múltiples y enrevesadas subconsultas.

El Corazón de la Magia: La Cláusula OVER()

Toda función de ventana se define por la cláusula OVER(). Esta cláusula especifica el conjunto de filas, o la "ventana", sobre la que operará la función. La sintaxis general es:

FUNCION_DE_VENTANA() OVER (PARTITION BY ... ORDER BY ...)

Sus componentes clave son:

  • PARTITION BY (Opcional): Divide las filas en particiones o grupos. Es el equivalente de GROUP BY, pero no colapsa las filas. La función se reiniciará para cada nueva partición.
  • ORDER BY (A menudo obligatorio): Ordena las filas dentro de cada partición. Es fundamental para las funciones de ranking y desplazamiento, ya que define qué fila es la "primera", "siguiente" y "anterior".

Funciones de Ranking: Creando Tablas de Clasificación

Una de las aplicaciones más poderosas de las funciones de ventana es la clasificación. La elección entre ellas depende de cómo quieras manejar los empates.

ROW_NUMBER(): El Numerador Estricto

Asigna un número de fila único y secuencial a cada registro dentro de su partición. No le importan los empates; si dos filas tienen el mismo valor, les asignará números diferentes.

SELECT
    Nombre,
    Departamento,
    Salario,
    ROW_NUMBER() OVER(PARTITION BY Departamento ORDER BY Salario DESC) AS Fila
FROM Empleados;

RANK(): El Ranking Olímpico

Asigna un rango a cada fila y sí se fija en los empates. Si dos filas tienen el mismo valor, se les asigna el mismo rango. Sin embargo, después de un empate, salta los rangos siguientes (ej. 1, 2, 2, 4).

SELECT
    Nombre,
    Departamento,
    Salario,
    RANK() OVER(PARTITION BY Departamento ORDER BY Salario DESC) AS Ranking
FROM Empleados;

DENSE_RANK(): El Ranking sin Huecos

También asigna el mismo rango a los valores empatados, pero su gran diferencia es que no salta los rangos siguientes. La secuencia es "densa" o consecutiva (ej. 1, 2, 2, 3).

SELECT
    Nombre,
    Departamento,
    Salario,
    DENSE_RANK() OVER(PARTITION BY Departamento ORDER BY Salario DESC) AS RankingDenso
FROM Empleados;

Funciones de Desplazamiento: Viajando en el Tiempo con LEAD y LAG

Estas funciones te permiten acceder a los datos de filas anteriores o posteriores a la fila actual dentro de su partición, sin necesidad de realizar un complejo SELF JOIN.

LAG(): Mirando hacia el Pasado

La función LAG() te permite obtener el valor de una columna de una fila anterior. Su sintaxis es LAG(columna, [desplazamiento], [valor_por_defecto]) OVER (...).

Es perfecta para calcular el crecimiento de ventas de un mes con respecto al anterior.

SELECT
    Mes,
    Ventas,
    LAG(Ventas, 1, 0) OVER (ORDER BY Mes) AS VentasMesAnterior,
    Ventas - LAG(Ventas, 1, 0) OVER (ORDER BY Mes) AS CrecimientoMensual
FROM VentasMensuales;

LEAD(): Mirando hacia el Futuro

La función LEAD() hace lo contrario: te permite obtener el valor de una columna de una fila posterior. Su sintaxis es LEAD(columna, [desplazamiento], [valor_por_defecto]) OVER (...).

SELECT
    Mes,
    Ventas,
    LEAD(Ventas, 1, 0) OVER (ORDER BY Mes) AS VentasMesSiguiente
FROM VentasMensuales;

Funciones de Ventana Agregadas: Totales Acumulados y Medias Móviles

Puedes usar funciones de agregación como SUM(), AVG() y COUNT() como funciones de ventana. La diferencia clave es que no colapsan las filas.

Totales Acumulados (Running Totals)

Un total acumulado es una suma que crece con cada fila. Es muy difícil de lograr sin funciones de ventana.

SELECT
    Mes,
    Ventas,
    SUM(Ventas) OVER (ORDER BY Mes) AS TotalAcumulado
FROM VentasMensuales;

Medias Móviles (Moving Averages)

Una media móvil calcula el promedio sobre una "ventana deslizante" de filas, útil para suavizar fluctuaciones y ver tendencias. Para esto, se usa la subcláusula ROWS BETWEEN.

SELECT
    Mes,
    Ventas,
    AVG(Ventas) OVER (
        ORDER BY Mes
        ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
    ) AS MediaMovil2Meses
FROM VentasMensuales;

Conclusión: Un Nuevo Nivel de Análisis a tu Alcance

Las funciones de ventana son una de las herramientas más expresivas y potentes del arsenal de SQL. Te permiten realizar análisis complejos que mantienen el contexto de cada fila individual.

Hoy hemos aprendido a:

  • Entender la cláusula OVER() como el motor que define la "ventana" de datos.
  • Utilizar ROW_NUMBER(), RANK() y DENSE_RANK() para crear clasificaciones sofisticadas.
  • Viajar en el tiempo a través de nuestros datos con LEAD() y LAG().
  • Calcular totales acumulados y medias móviles usando funciones de agregación sobre una ventana.

En nuestro próximo artículo, exploraremos las Expresiones de Tabla Comunes (CTEs), una técnica para organizar consultas complejas y hacer que nuestro código, incluidas las funciones de ventana, sea aún más legible y mantenible.