← Volver

Ejercicios SQL — Nivel Avanzado + Experto

SQL Avanzado

1) JOIN de 5 tablas (ventas completas)

Obtener ventas con cliente, item, producto, categoría y precio vigente.

SELECT o.OrdenID, o.Fecha, c.Nombre AS Cliente, p.Nombre AS Producto, cat.Nombre AS Categoria, ph.Precio FROM Ordenes o JOIN Clientes c ON o.ClienteID = c.ClienteID JOIN OrdenItems i ON o.OrdenID = i.OrdenID JOIN Productos p ON i.ProductoID = p.ProductoID JOIN Categorias cat ON p.CategoriaID = cat.CategoriaID LEFT JOIN PriceHistory ph ON ph.ProductoID = p.ProductoID AND o.Fecha BETWEEN ph.VigenciaDesde AND ph.VigenciaHasta;

2) Subconsulta correlacionada — detectar últimas compras

SELECT * FROM Ordenes o WHERE Fecha = ( SELECT MAX(Fecha) FROM Ordenes WHERE ClienteID = o.ClienteID );

3) Total acumulado por cliente + diferencia mensual

SELECT ClienteID, Fecha, SUM(Total) OVER (PARTITION BY ClienteID ORDER BY Fecha) AS Acumulado, Total - LAG(Total) OVER (PARTITION BY ClienteID ORDER BY Fecha) AS Variacion FROM Ordenes;

SQL Experto (FAANG / Big Tech / Bancos)

1) Gaps & Islands — detectar períodos sin ventas

WITH Fechas AS ( SELECT Fecha, DATE_SUB(Fecha, INTERVAL ROW_NUMBER() OVER (ORDER BY Fecha) DAY) AS Grupo FROM Ordenes ) SELECT MIN(Fecha) AS Inicio, MAX(Fecha) AS Fin FROM Fechas GROUP BY Grupo ORDER BY Inicio;

2) SCD Tipo 2 — recuperar precio vigente por fecha

SELECT p.ProductoID, p.Nombre, ph.Precio FROM Productos p JOIN PriceHistory ph ON ph.ProductoID = p.ProductoID AND CURRENT_DATE BETWEEN ph.VigenciaDesde AND ph.VigenciaHasta;

3) Deduplicación avanzada sin DISTINCT

DELETE FROM Transacciones t WHERE t.ctid NOT IN ( SELECT MIN(ctid) FROM Transacciones GROUP BY ClienteID, Fecha, Monto );

Data Engineering — Problemas Reales

1)Reconciliación entre dos fuentes (diff)

SELECT a.ProductoID, a.Stock AS StockA, b.Stock AS StockB FROM InventarioA a LEFT JOIN InventarioB b ON a.ProductoID = b.ProductoID WHERE COALESCE(a.Stock,0) != COALESCE(b.Stock,0) UNION SELECT b.ProductoID, a.Stock AS StockA, b.Stock AS StockB FROM InventarioB b LEFT JOIN InventarioA a ON a.ProductoID = b.ProductoID WHERE COALESCE(a.Stock,0) != COALESCE(b.Stock,0);

2) Pivot Complejo (ventas por mes por región)

SELECT Region, SUM(CASE WHEN Mes = 1 THEN Total END) AS Enero, SUM(CASE WHEN Mes = 2 THEN Total END) AS Febrero, SUM(CASE WHEN Mes = 3 THEN Total END) AS Marzo FROM ( SELECT Region, EXTRACT(MONTH FROM Fecha) AS Mes, Total FROM Ordenes o JOIN Sucursales s ON o.SucursalID = s.SucursalID ) t GROUP BY Region;

3) Limpieza de datos — estandarizar nombres

UPDATE Clientes SET Nombre = INITCAP(TRIM(REPLACE(Nombre,' ',' ')));

Query Tuning (Optimización)

1) Transformar subquery lenta en JOIN

Consultas lentas:

SELECT * FROM Ordenes WHERE ClienteID IN (SELECT ClienteID FROM Clientes WHERE Activo = TRUE);

Optimizada:

SELECT o.* FROM Ordenes o JOIN Clientes c ON o.ClienteID = c.ClienteID WHERE c.Activo = TRUE;

2) Reescritura para usar índices

-- EVITAR funciones sobre columnas indexadas: -- NO: WHERE DATE(Fecha) = '2023-10-01' -- SÍ: WHERE Fecha >= '2023-10-01' AND Fecha < '2023-10-02';

3) Identificar FULL SCAN y evitarlo

EXPLAIN SELECT * FROM Ordenes WHERE Total > 5000;

→ Crear índice:

CREATE INDEX idx_ordenes_total ON Ordenes(Total);

Dataset Completo para los Ejercicios

  • Clientes (ClienteID, Nombre, Pais, Activo)
  • Sucursales (SucursalID, Nombre, Region)
  • Productos (ProductoID, Nombre, CategoriaID)
  • PriceHistory (ProductoID, Precio, VigenciaDesde, VigenciaHasta)
  • Categorias (CategoriaID, Nombre, PadreID)
  • Ordenes (OrdenID, ClienteID, Fecha, Total, SucursalID)
  • OrdenItems (ItemID, OrdenID, ProductoID, Cantidad, Total)
  • InventarioA / InventarioB (ProductoID, Stock)
  • Transacciones (ID, ClienteID, Fecha, Monto)
  • AuditLogs (ID, Tabla, Operacion, Fecha, Usuario)
whatsapp