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