/

/

SQL Window Functions: Funciones de Ventana Explicadas

Content

SQL Window Functions: Funciones de Ventana Explicadas

SQL Window Functions: Funciones de Ventana Explicadas

¿Qué son las Window Functions?

Las funciones de ventana (window functions) realizan cálculos sobre un conjunto de filas relacionadas con la fila actual, sin agrupar los resultados en una sola fila como hace GROUP BY.

Diferencia con GROUP BY

Con GROUP BY

SELECT departamento, AVG(salario) as promedio
 FROM empleados
 GROUP BY departamento;
 -- Resultado: 1 fila por departamento

Con Window Function

SELECT
  nombre,
  departamento,
  salario,
  AVG(salario) OVER (PARTITION BY departamento) as promedio_depto
 FROM empleados;
 -- Resultado: mantiene todas las filas, añade el promedio

---

Sintaxis Básica

FUNCION() OVER (
  [PARTITION BY columna]
  [ORDER BY columna]
  [ROWS/RANGE BETWEEN ... AND ...]
 )

---

Funciones de Ranking

ROW_NUMBER()

Asigna un número único secuencial:

SELECT
  nombre,
  departamento,
  salario,
  ROW_NUMBER() OVER (ORDER BY salario DESC) as ranking
 FROM empleados;

| nombre | departamento | salario | ranking |

|--------|--------------|---------|---------|

| Ana | Ventas | 80000 | 1 |

| Carlos | IT | 75000 | 2 |

| María | Ventas | 75000 | 3 |


RANK()

Igual ranking para valores iguales, salta números:

SELECT
  nombre,
  salario,
  RANK() OVER (ORDER BY salario DESC) as ranking
 FROM empleados;

| nombre | salario | ranking |

|--------|---------|---------|

| Ana | 80000 | 1 |

| Carlos | 75000 | 2 |

| María | 75000 | 2 |

| Pedro | 60000 | 4 |


DENSE_RANK()

Como RANK pero sin saltar números:

SELECT
  nombre,
  salario,
  DENSE_RANK() OVER (ORDER BY salario DESC) as ranking
 FROM empleados;

| nombre | salario | ranking |

|--------|---------|---------|

| Ana | 80000 | 1 |

| Carlos | 75000 | 2 |

| María | 75000 | 2 |

| Pedro | 60000 | 3 |


NTILE(n)

Divide en n grupos iguales:

SELECT
  nombre,
  salario,
  NTILE(4) OVER (ORDER BY salario DESC) as cuartil
 FROM empleados;

---

PARTITION BY

Divide los datos en grupos independientes:

SELECT
  nombre,
  departamento,
  salario,
  ROW_NUMBER() OVER (PARTITION BY departamento ORDER BY salario DESC) as ranking_depto
 FROM empleados;

| nombre | departamento | salario | ranking_depto |

|--------|--------------|---------|---------------|

| Ana | Ventas | 80000 | 1 |

| María | Ventas | 75000 | 2 |

| Carlos | IT | 75000 | 1 |

| Pedro | IT | 60000 | 2 |


---

Funciones de Agregación como Window

SELECT
  fecha,
  ventas,
  SUM(ventas) OVER (ORDER BY fecha) as ventas_acumuladas,
  AVG(ventas) OVER (ORDER BY fecha ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) as promedio_7_dias,
  COUNT(*) OVER (PARTITION BY MONTH(fecha)) as ventas_mes
 FROM ventas_diarias;

---

LAG y LEAD

LAG - Valor de Fila Anterior

SELECT
  fecha,
  ventas,
  LAG(ventas, 1) OVER (ORDER BY fecha) as ventas_ayer,
  ventas - LAG(ventas, 1) OVER (ORDER BY fecha) as diferencia
 FROM ventas_diarias;

| fecha | ventas | ventas_ayer | diferencia |

|-------|--------|-------------|------------|

| 2024-01-01 | 100 | NULL | NULL |

| 2024-01-02 | 150 | 100 | 50 |

| 2024-01-03 | 120 | 150 | -30 |


LEAD - Valor de Fila Siguiente

SELECT
  fecha,
  ventas,
  LEAD(ventas, 1) OVER (ORDER BY fecha) as ventas_manana
 FROM ventas_diarias;

---

FIRST_VALUE y LAST_VALUE

SELECT
  nombre,
  departamento,
  salario,
  FIRST_VALUE(nombre) OVER (
  PARTITION BY departamento
  ORDER BY salario DESC
  ) as mejor_pagado_depto
 FROM empleados;

---

Frame Specification (ROWS/RANGE)

Define qué filas incluir en el cálculo:

ROWS BETWEEN

SELECT
  fecha,
  ventas,
  -- Promedio móvil de 7 días
  AVG(ventas) OVER (
  ORDER BY fecha
  ROWS BETWEEN 6 PRECEDING AND CURRENT ROW
  ) as promedio_7d,
  -- Suma de las 3 siguientes filas
  SUM(ventas) OVER (
  ORDER BY fecha
  ROWS BETWEEN CURRENT ROW AND 3 FOLLOWING
  ) as suma_proximas_3
 FROM ventas_diarias;

Opciones de Frame

| Especificación | Significado |

|----------------|-------------|

| UNBOUNDED PRECEDING | Desde el inicio |

| n PRECEDING | n filas antes |

| CURRENT ROW | Fila actual |

| n FOLLOWING | n filas después |

| UNBOUNDED FOLLOWING | Hasta el final |


---

Casos de Uso Prácticos

1. Top N por Categoría

WITH ranked AS (
  SELECT
  *,
  ROW_NUMBER() OVER (
  PARTITION BY categoria
  ORDER BY ventas DESC
  ) as rn
  FROM productos
 )
 SELECT * FROM ranked WHERE rn <= 3;

2. Porcentaje del Total

SELECT
  producto,
  categoria,
  ventas,
  ROUND(
  100.0 * ventas / SUM(ventas) OVER (PARTITION BY categoria),
  2
  ) as porcentaje_categoria,
  ROUND(
  100.0 * ventas / SUM(ventas) OVER (),
  2
  ) as porcentaje_total
 FROM ventas;

3. Crecimiento Mes a Mes

SELECT
  mes,
  ingresos,
  LAG(ingresos) OVER (ORDER BY mes) as ingresos_anterior,
  ROUND(
  100.0 * (ingresos - LAG(ingresos) OVER (ORDER BY mes))
  / LAG(ingresos) OVER (ORDER BY mes),
  2
  ) as crecimiento_pct
 FROM ingresos_mensuales;

4. Running Total (Acumulado)

SELECT
  fecha,
  monto,
  SUM(monto) OVER (ORDER BY fecha) as acumulado
 FROM transacciones;

5. Encontrar Gaps en Secuencias

SELECT
  id,
  LEAD(id) OVER (ORDER BY id) as siguiente_id,
  LEAD(id) OVER (ORDER BY id) - id as gap
 FROM registros
 HAVING gap > 1;

---

Window Functions vs Subconsultas

Con Subconsulta (menos eficiente)

SELECT
  e.*,
  (SELECT AVG(salario) FROM empleados WHERE departamento = e.departamento) as avg_depto
 FROM empleados e;

Con Window Function (más eficiente)

SELECT
  *,
  AVG(salario) OVER (PARTITION BY departamento) as avg_depto
 FROM empleados;

---

Múltiples Windows

Puedes definir múltiples ventanas con nombres:

SELECT
  nombre,
  departamento,
  salario,
  AVG(salario) OVER w as promedio,
  MAX(salario) OVER w as maximo
 FROM empleados
 WINDOW w AS (PARTITION BY departamento);

---

Errores Comunes

1. ORDER BY Faltante en Ranking

-- Error: rankings inconsistentes
 ROW_NUMBER() OVER ()


2. Confundir ROWS con RANGE

ROWS cuenta filas físicas, RANGE agrupa valores iguales.

3. LAST_VALUE sin Frame

-- Problema: el frame por defecto no incluye todas las filas
 LAST_VALUE(x) OVER (ORDER BY y)


---

Conclusión

Las window functions son una herramienta poderosa que simplifica análisis complejos. Dominarlas te permite crear reportes avanzados con código más limpio y eficiente.

---

Tip: Usa AI2sql para generar consultas con window functions automáticamente. La IA puede ayudarte a crear análisis complejos en segundos.

Share this

More Articles