Nivel 1 – Subconsultas (1–7)

1) Productos con precio mayor al promedio

Solución
SELECT nombre, precio
FROM productos
WHERE precio > (SELECT AVG(precio) FROM productos);

2) Clientes que tienen ventas (IN)

Solución
SELECT nombre
FROM clientes
WHERE id_cliente IN (SELECT id_cliente FROM ventas);

3) Clientes que NO tienen ventas

Solución
SELECT nombre
FROM clientes
WHERE id_cliente NOT IN (SELECT id_cliente FROM ventas);

4) Clientes que tienen ventas (EXISTS)

Solución
SELECT c.nombre
FROM clientes c
WHERE EXISTS (SELECT 1 FROM ventas v WHERE v.id_cliente = c.id_cliente);

5) Clientes con 3 o más ventas (correlacionada)

Solución
SELECT c.nombre
FROM clientes c
WHERE 3 <= (SELECT COUNT(*) FROM ventas v WHERE v.id_cliente = c.id_cliente);

6) Ventas por encima del promedio de ventas

Solución
SELECT *
FROM ventas
WHERE total > (SELECT AVG(total) FROM ventas);

7) Producto más caro (subconsulta)

Solución
SELECT *
FROM productos
WHERE precio = (SELECT MAX(precio) FROM productos);

Nivel 2 – CTE (8–13)

8) CTE: monto total por cliente

Solución
WITH t AS (
  SELECT id_cliente, SUM(total) AS monto_total
  FROM ventas
  GROUP BY id_cliente
)
SELECT * FROM t ORDER BY monto_total DESC;

9) CTE + JOIN: nombre del cliente y su monto_total

Solución
WITH t AS (
  SELECT id_cliente, SUM(total) AS monto_total
  FROM ventas
  GROUP BY id_cliente
)
SELECT c.nombre, t.monto_total
FROM t
INNER JOIN clientes c ON c.id_cliente = t.id_cliente
ORDER BY t.monto_total DESC;

10) CTE: clientes con monto_total >= 500

Solución
WITH t AS (
  SELECT id_cliente, SUM(total) AS monto_total
  FROM ventas
  GROUP BY id_cliente
)
SELECT c.nombre, t.monto_total
FROM t
INNER JOIN clientes c ON c.id_cliente = t.id_cliente
WHERE t.monto_total >= 500
ORDER BY t.monto_total DESC;

11) CTE recursivo: números 1..20

Solución
WITH nums AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM nums WHERE n < 20
)
SELECT n FROM nums
OPTION (MAXRECURSION 100);

12) CTE recursivo: generar días 1..7 (ejemplo)

Solución
WITH dias AS (
  SELECT CAST('2025-01-01' AS date) AS d
  UNION ALL
  SELECT DATEADD(day, 1, d) FROM dias WHERE d < '2025-01-07'
)
SELECT d FROM dias
OPTION (MAXRECURSION 100);

13) CTE: top 5 clientes por monto_total

Solución
WITH t AS (
  SELECT id_cliente, SUM(total) AS monto_total
  FROM ventas
  GROUP BY id_cliente
)
SELECT TOP 5 c.nombre, t.monto_total
FROM t
INNER JOIN clientes c ON c.id_cliente = t.id_cliente
ORDER BY t.monto_total DESC;

Nivel 3 – Window Functions (14–20)

14) ROW_NUMBER: numerar ventas por cliente (recientes primero)

Solución
SELECT v.*,
       ROW_NUMBER() OVER (PARTITION BY id_cliente ORDER BY fecha DESC) AS rn
FROM ventas v;

15) Última venta por cliente

Solución
WITH x AS (
  SELECT v.*,
         ROW_NUMBER() OVER (PARTITION BY id_cliente ORDER BY fecha DESC) AS rn
  FROM ventas v
)
SELECT * FROM x WHERE rn = 1;

16) Ranking de clientes por monto_total

Solución
WITH t AS (
  SELECT id_cliente, SUM(total) AS monto_total
  FROM ventas
  GROUP BY id_cliente
)
SELECT t.*,
       DENSE_RANK() OVER (ORDER BY monto_total DESC) AS ranking
FROM t
ORDER BY monto_total DESC;

17) Total global y porcentaje por venta

Solución
SELECT id_venta, total,
       SUM(total) OVER() AS total_global,
       CAST(100.0 * total / SUM(total) OVER() AS decimal(10,2)) AS porcentaje
FROM ventas;

18) Acumulado por cliente (por fecha)

Solución
SELECT id_cliente, fecha, total,
       SUM(total) OVER (
         PARTITION BY id_cliente
         ORDER BY fecha
         ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
       ) AS acumulado
FROM ventas;

19) Promedio global disponible en cada fila

Solución
SELECT id_venta, total,
       AVG(total) OVER() AS promedio_global
FROM ventas;

20) Top 2 ventas por cliente (ROW_NUMBER)

Solución
WITH x AS (
  SELECT v.*,
         ROW_NUMBER() OVER (PARTITION BY id_cliente ORDER BY total DESC) AS rn
  FROM ventas v
)
SELECT * FROM x
WHERE rn <= 2
ORDER BY id_cliente, rn;