Tema 12: Window functions: ranking, LAG, LEAD y promedios móviles
Identificador: PF-012 | XP: 200 | Insignia: 🥇 Oro | Tier: Aprendiz
Tiempo estimado: 90-120 min | Pre-requisitos: PF-009, PF-011
🖼️ Imagen de inicio del tema

[Moka con telescopio mexica mirando pirámide escalonada (window). Sofía, Don Carlos, Citlalli viendo rankings de productos.]
🎯 Aprenderás
🏛️ Visión mexica — Por Citlalli
"Los calpixqui organizaban los altépetl tributarios por jerarquía: el primero en llegar al huey tlatoani era el más importante. Esa 'jerarquía dinámica' es el equivalente de una WINDOW FUNCTION en SQL: calcular un valor (ranking, suma acumulada) sobre un grupo de filas sin perder la fila individual.
El tonalpohualli (calendario mexica de 260 días) era un sistema de 'ventanas temporales': cada día era único pero formaba parte de una trecena, un mes, un año. Lo mismo hace una window function: cada fila es única pero forma parte de un grupo."
📚 Bloque 1: ROW_NUMBER, RANK, DENSE_RANK
SELECT
nombre,
precio,
ROW_NUMBER() OVER (ORDER BY precio DESC) AS fila,
RANK() OVER (ORDER BY precio DESC) AS ranking,
DENSE_RANK() OVER (ORDER BY precio DESC) AS ranking_denso
FROM productos;- `ROW_NUMBER`: número único, no salta.
- `RANK`: si hay empates, salta el siguiente número.
- `DENSE_RANK`: si hay empates, no salta.
📚 Bloque 2: LAG y LEAD
-- Comparar ventas de cada mes con el mes anterior
SELECT
DATE_FORMAT(fecha_pedido, '%Y-%m') AS mes,
SUM(total) AS ventas_mes,
LAG(SUM(total), 1) OVER (ORDER BY DATE_FORMAT(fecha_pedido, '%Y-%m')) AS mes_anterior,
SUM(total) - LAG(SUM(total), 1) OVER (ORDER BY DATE_FORMAT(fecha_pedido, '%Y-%m')) AS diferencia
FROM pedidos
GROUP BY DATE_FORMAT(fecha_pedido, '%Y-%m');📚 Bloque 3: SUM OVER PARTITION BY — suma acumulada por grupo
-- Para cada cliente, sus pedidos con total acumulado
SELECT
c.nombre,
pe.fecha_pedido,
pe.total,
SUM(pe.total) OVER (PARTITION BY c.id ORDER BY pe.fecha_pedido) AS acumulado
FROM clientes c
INNER JOIN pedidos pe ON c.id = pe.cliente_id
ORDER BY c.nombre, pe.fecha_pedido;📚 Bloque 4: NTILE — dividir en grupos iguales
-- Dividir productos en 4 grupos de precio (cuartiles)
SELECT
nombre,
precio,
NTILE(4) OVER (ORDER BY precio) AS cuartil
FROM productos;📚 Bloque 5: ROW_NUMBER para "top N por grupo"
-- Top 3 productos más vendidos por categoría
WITH ranked AS (
SELECT
categoria_id,
nombre,
total_vendido,
ROW_NUMBER() OVER (PARTITION BY categoria_id ORDER BY total_vendido DESC) AS ranking
FROM (
SELECT pr.categoria_id, pr.nombre, SUM(pi.cantidad) AS total_vendido
FROM productos pr
INNER JOIN pedido_items pi ON pr.id = pi.producto_id
GROUP BY pr.categoria_id, pr.nombre
) sub
)
SELECT FROM ranked WHERE ranking <= 3;🤖 AI Mission
Pídele: "Dame 5 ejemplos de uso real de window functions en un e-commerce. Para cada uno, escribe la query y explica el patrón."*
⚠️ Errores típicos
🧪 LAB 12.1 — "5 reportes con window functions"
📝 Quest 12
✅ Respuestas
1-B, 2-B, 3-B, 4-A, 5-B, 6-B, 7-B, 8-A, 9-B, 10-B.
🏛️ Tras las huellas — Por Citlalli
"Los calpixqui organizaban altépetl por jerarquía dinámica: el primero en llegar al huey tlatoani era el más importante. Esa es una WINDOW FUNCTION: calcular un valor (ranking, suma acumulada) sobre un grupo sin perder la fila individual."
📓 Cierre
1. La window function más útil fue:
2. La query más compleja:
3. Una decisión de negocio con LAG/LEAD:
4. Cómo voy a usar window functions:
🚀 ¿Qué sigue?
Tema 13 — Vistas, índices y constraints: el kit de durabilidad.