Adiós al Infierno de las Subconsultas
Dominando Common Table Expressions (CTEs)
El Problema: El "Infierno de las Subconsultas"
A medida que la lógica de negocio se vuelve más compleja, nuestras consultas SQL pueden convertirse en un laberinto de subconsultas anidadas, difíciles de leer, depurar y mantener.
SELECT ...
FROM (
SELECT ...
FROM (
SELECT ...
FROM tabla_A
WHERE ...
) subconsulta_1
JOIN tabla_B ON ...
) subconsulta_2
WHERE ...
La Solución: Modularidad con CTEs
Un Common Table Expression (CTE) es una **tabla temporal con nombre** que existe solo durante la ejecución de una consulta. Nos permite dividir una consulta compleja en bloques lógicos y reutilizables.
Piensa en ellos como variables en programación: asignas un nombre a un resultado intermedio para usarlo más adelante.
WITH nombre_cte_1 AS (
-- Lógica del primer paso
SELECT ... FROM ...
),
nombre_cte_2 AS (
-- Lógica que puede usar nombre_cte_1
SELECT ... FROM nombre_cte_1
)
-- Consulta final que usa los CTEs
SELECT ... FROM nombre_cte_2;
El "Antes": Un Reporte Complejo
**Caso de negocio:** Necesitamos un reporte que muestre el total de ventas y el número de pedidos por cliente, pero solo para aquellos clientes de 'Bogotá D.C.' que hayan gastado más de $500 en total.
SELECT
nombre_usuario,
email,
total_gastado,
numero_pedidos
FROM (
SELECT
u.id_usuario,
u.nombre_usuario,
u.email,
p.total_gastado,
p.numero_pedidos
FROM curso_arquitecturas.usuarios_silver u
JOIN (
SELECT
id_usuario,
SUM(monto_total) AS total_gastado,
COUNT(id_pedido) AS numero_pedidos
FROM curso_arquitecturas.pedidos_silver
GROUP BY id_usuario
) p ON u.id_usuario = p.id_usuario
WHERE
u.ciudad = 'Bogotá D.C.'
) AS reporte_clientes
WHERE
total_gastado > 500;
El "Después": Lógica Clara con CTEs
Refactorizamos la consulta usando dos CTEs: uno para agregar los pedidos y otro para filtrar a los clientes.
WITH ResumenPedidos AS (
-- Paso 1: Agregamos los datos de los pedidos por usuario.
SELECT
id_usuario,
SUM(monto_total) AS total_gastado,
COUNT(id_pedido) AS numero_pedidos
FROM curso_arquitecturas.pedidos_silver
GROUP BY id_usuario
),
ClientesBogota AS (
-- Paso 2: Unimos el resumen con los usuarios y filtramos por ciudad.
SELECT
u.nombre_usuario,
u.email,
rp.total_gastado,
rp.numero_pedidos
FROM curso_arquitecturas.usuarios_silver u
JOIN ResumenPedidos rp ON u.id_usuario = rp.id_usuario
WHERE u.ciudad = 'Bogotá D.C.'
)
-- Paso 3: Aplicamos el filtro final sobre el resultado intermedio.
SELECT *
FROM ClientesBogota
WHERE total_gastado > 500;
Visualizando el Flujo de Datos
Los CTEs crean un pipeline de datos claro y secuencial dentro de nuestra consulta.
¡A Practicar!
**Nuevo reto:** Genera un reporte que muestre el producto más vendido (en cantidad) por cada categoría. Debes mostrar el nombre de la categoría, el nombre del producto y la cantidad total vendida.
-- Pista: Necesitarás un CTE para sumar las cantidades por producto,
-- y luego otro CTE o una función de ventana para encontrar el ranking
-- de productos dentro de cada categoría.
-- Tablas a usar: pedidos_silver y productos_silver
Módulo 2: Análisis de Secuencias y Comparativas
Desbloqueando Análisis con Funciones de Ventana