Lección 2 de 29· Bienvenida: SQL de nivel profesional
GROUP BY no puedeYa sabes resumir datos con GROUP BY y combinar tablas con JOIN. Con eso puedes responder "¿cuánto vendimos en total?" o "¿cuánto vendimos cada día?". Pero hay una pregunta que a GROUP BY se le atraganta:
¿Cuánto llevábamos vendido acumulado al final de cada día?
Eso es un total acumulado (running total): la venta de hoy más todo lo de días anteriores. Es el pan de cada día de cualquier informe financiero... y con GROUP BY solo es un dolor de cabeza. Con una función de ventana son tres líneas.
No vamos a explicar toda la sintaxis todavía (para eso están los módulos siguientes). El plan de esta lección es simple: ejecuta el bloque de abajo, mira el resultado, y siente que ya hiciste algo. Estás sobre un PostgreSQL real, en el navegador, con los datos de la tienda TechAndino.
Pulsa Ejecutar en este bloque. Calcula, para cada fecha con pedidos completados, la venta del día y el total acumulado hasta ese día.
SELECT o.order_date,
SUM(oi.quantity * oi.unit_price) AS ventas_del_dia,
SUM(SUM(oi.quantity * oi.unit_price))
OVER (ORDER BY o.order_date) AS total_acumulado
FROM orders o
JOIN order_items oi ON oi.order_id = o.order_id
WHERE o.status = 'completado'
GROUP BY o.order_date
ORDER BY o.order_date;¿Lo viste? La columna total_acumulado sube y sube: cada fila suma su propio día más todo lo anterior. La primera fila vale lo mismo que su venta del día; la última es el total de la tienda. Eso es un total acumulado, y lo hiciste en una sola consulta.
La parte mágica es esta:
SUM(...) OVER (ORDER BY o.order_date)La palabra clave es OVER. Convierte un agregado normal (SUM) en una función de ventana: en lugar de colapsar las filas, recorre las filas en el orden que le indicas (ORDER BY o.order_date) y va acumulando. El SUM interior calcula la venta de cada día; el SUM ... OVER exterior las va sumando una tras otra. No te preocupes por la anidación todavía: solo quédate con que OVER es lo que la hace acumular.
GROUP BY colapsa, la ventana conservaAquí está el contraste en una frase: GROUP BY reduce muchas filas a una por grupo; una función de ventana deja todas las filas en su sitio y añade el cálculo como una columna más.
Míralo tú: este GROUP BY "clásico" te da el gran total... pero una sola fila. Perdiste el detalle día a día.
-- GROUP BY clásico: colapsa TODO en una sola fila
SELECT SUM(oi.quantity * oi.unit_price) AS ventas_totales
FROM orders o
JOIN order_items oi ON oi.order_id = o.order_id
WHERE o.status = 'completado';El primer bloque conservaba una fila por fecha y además mostraba el acumulado al lado. Este segundo bloque te da el número final (5910... el mismo que la última fila del acumulado), pero nada más. Esa capacidad de calcular sin colapsar es toda la razón de existir de las funciones de ventana, y es lo que vas a dominar en este curso.
Para que la idea se te quede grabada, este es el total acumulado de un solo vendedor (Jorge Salas) a lo largo del año. La línea del acumulado solo puede subir; la de la venta del día salta según lo que se vendió esa fecha.
Tres ideas que llevas de esta lección (guárdalas: te acompañarán todo el curso):
Cierra con una pequeña victoria propia. Abajo tienes casi lista una consulta que calcula el total acumulado de los pedidos completados de Jorge Salas (employee_id = 4). La columna acumulado está puesta en NULL: reemplázala por la función de ventana correcta, ejecuta y pulsa Comprobar.
Si lo consigues, la última fila debe marcar 5910.00 de acumulado. 🚀
Completa la columna acumulado: reemplaza NULL por una función de ventana que sume, en orden de fecha, la venta de cada día. El resultado debe tener 4 filas y la última debe mostrar 5910.00 en acumulado.
-- Total acumulado de los pedidos completados de Jorge Salas (employee_id = 4).
-- Reemplaza NULL por una función de ventana que acumule la venta de cada día.
SELECT o.order_date,
SUM(oi.quantity * oi.unit_price) AS ventas_dia,
NULL AS acumulado -- TODO: SUM(...) OVER (ORDER BY o.order_date)
FROM orders o
JOIN order_items oi ON oi.order_id = o.order_id
WHERE o.status = 'completado' AND o.employee_id = 4
GROUP BY o.order_date
ORDER BY o.order_date;¿Verde? Acabas de escribir tu primera función de ventana. Y ya intuyes la idea más importante del curso: cuando quieras un cálculo por fila que mire a otras filas —acumulados, rankings, comparaciones con el día anterior, medias móviles— la respuesta casi siempre empieza con OVER (...).
En el resto del curso desglosaremos OVER pieza por pieza (PARTITION BY, el marco ROWS BETWEEN, ROW_NUMBER, RANK, LAG, LEAD...), además de CTEs, recursión y optimización. Pero el clic mental ya lo diste. En la próxima lección conocerás a fondo el dataset de TechAndino sobre el que construiremos todo.
Gratis