Has superado los fundamentos. Es hora de profundizar en técnicas avanzadas que te permitirán optimizar
consultas, manejar datos complejos y construir soluciones robustas en SQL Server.
Módulo 1: Funciones Avanzadas y Procesamiento de Datos
Las funciones son herramientas poderosas que transforman y analizan tus datos directamente en las
consultas, evitando procesamiento manual.
Lección 1.1: Funciones de cadena (LEN, SUBSTRING, REPLACE)
Las funciones de cadena te permiten manipular texto. LEN() obtiene la longitud,
SUBSTRING() extrae parte del texto, y REPLACE() sustituye caracteres.
-- Obtener la longitud del nombre del cliente
SELECT Nombre, LEN(Nombre) AS LongitudNombre
FROM Clientes;
-- Extraer los primeros 3 caracteres del código postal
SELECT CodigoPostal, SUBSTRING(CodigoPostal, 1, 3) AS Prefijo
FROM Direcciones;
-- Reemplazar 'Sr.' por 'Señor' en los títulos
SELECT REPLACE(Titulo, 'Sr.', 'Señor') AS TituloCompleto
FROM Empleados;
Lección 1.2: Funciones de fecha (GETDATE, DATEADD, DATEDIFF)
Trabajar con fechas es común. GETDATE() obtiene la fecha actual, DATEADD()
suma/resta tiempo, y DATEDIFF() calcula la diferencia entre fechas.
-- Fecha y hora actual del sistema
SELECT GETDATE() AS FechaActual;
-- Pedidos realizados hace exactamente 30 días
SELECT * FROM Pedidos
WHERE FechaPedido = DATEADD(DAY, -30, GETDATE());
-- Días transcurridos desde cada pedido
SELECT PedidoID, DATEDIFF(DAY, FechaPedido, GETDATE()) AS DiasTranscurridos
FROM Pedidos;
Redondean números según tus necesidades. ROUND() redondea al entero más cercano o a
decimales específicos, CEILING() redondea siempre hacia arriba, y FLOOR()
hacia abajo.
-- Redondear precios a 2 decimales
SELECT Producto, Precio, ROUND(Precio, 2) AS PrecioRedondeado
FROM Productos;
-- Obtener el número de empleados redondeado hacia arriba
SELECT CEILING(AVG(Edad)) AS EdadPromedioRedondeada
FROM Empleados;
Lección 1.4: CASE WHEN para lógica condicional
CASE WHEN es como un "if-else" dentro de SQL. Te permite crear nuevas columnas basadas
en condiciones.
-- Clasificar clientes por nivel de gasto
SELECT ClienteID, Nombre,
CASE
WHEN TotalCompras > 5000 THEN 'VIP'
WHEN TotalCompras > 1000 THEN 'Regular'
ELSE 'Nuevo'
END AS CategoriaCliente
FROM Clientes;
Pro Tip: Usa funciones en la cláusula SELECT para transformar datos sin
modificar la tabla original. Esto mantiene la integridad de tus datos fuente.
Ejercicios de Práctica del Módulo 1
Escribe una consulta que muestre el nombre completo de los empleados en mayúsculas y cuente
cuántos caracteres tiene cada nombre.
Muestra todos los pedidos con su fecha original y la fecha con 7 días adicionales para
estimar entrega.
Crea una columna calculada que clasifique los productos como 'Caro' (precio > 100), 'Medio'
(50-100) o 'Barato' (< 50).
Calcula cuántos meses han pasado desde la contratación de cada empleado hasta hoy.
Redondea todos los salarios de la tabla Empleados al múltiplo de 100 más cercano.
Módulo 2: Agregación y Análisis de Datos
Transforma filas individuales en información resumida y significativa con funciones de agregación.
Lección 2.1: GROUP BY y funciones de agregación (COUNT,
SUM, AVG, MIN, MAX)
GROUP BY agrupa filas con valores idénticos. Las funciones de agregación calculan
valores totales por grupo.
-- Total de ventas por cliente
SELECT ClienteID, COUNT(*) AS TotalPedidos, SUM(Total) AS TotalVentas
FROM Pedidos
GROUP BY ClienteID;
Lección 2.2: HAVING para filtrar grupos
HAVING filtra grupos después de que se han calculado las agregaciones (a diferencia de
WHERE que filtra filas individuales).
-- Clientes que han gastado más de 1000€
SELECT ClienteID, SUM(Total) AS TotalGastado
FROM Pedidos
GROUP BY ClienteID
HAVING SUM(Total) > 1000;
Lección 2.3: Ordenamiento de resultados agregados
Puedes ordenar los resultados agrupados por las columnas calculadas.
-- Top 5 clientes con mayor gasto
SELECT TOP 5 ClienteID, SUM(Total) AS TotalGastado
FROM Pedidos
GROUP BY ClienteID
ORDER BY TotalGastado DESC;
Lección 2.4: ROLLUP y CUBE para subtotales
ROLLUP genera subtotales y un gran total. CUBE genera todos los posibles
subtotales.
-- Ventas por año y mes con subtotales
SELECT Año, Mes, SUM(Ventas) AS TotalVentas
FROM ReporteVentas
GROUP BY ROLLUP(Año, Mes);
Ejercicios de Práctica del Módulo 2
Calcula el número de productos y el precio promedio por categoría.
Encuentra las categorías que tienen más de 10 productos y ordena por cantidad descendente.
Muestra el empleado que ha realizado más ventas este mes.
Crea un reporte con el total vendido por día de la semana.
Utiliza ROLLUP para mostrar ventas por país, región y ciudad con subtotales.
Módulo 3: Subconsultas y Consultas Anidadas
Las subconsultas permiten realizar cálculos complejos en pasos separados, haciendo tus consultas más
potentes y flexibles.
Lección 3.1: Subconsultas en la cláusula WHERE (IN,
EXISTS)
Usa el resultado de una consulta para filtrar otra. IN comprueba pertenencia,
EXISTS verifica si existe al menos un resultado.
-- Clientes que han hecho pedidos
SELECT * FROM Clientes
WHERE ClienteID IN (SELECT DISTINCT ClienteID FROM Pedidos);
-- Productos que nunca se han vendido
SELECT * FROM Productos
WHERE NOT EXISTS (SELECT 1 FROM DetallesPedido WHERE ProductoID = Productos.ProductoID);
Lección 3.2: Subconsultas en FROM (tablas derivadas)
Puedes usar el resultado de una consulta como si fuera una tabla temporal.
-- Promedio de ventas por cliente
SELECT AVG(TotalVentas) AS PromedioVentas
FROM (
SELECT ClienteID, SUM(Total) AS TotalVentas
FROM Pedidos
GROUP BY ClienteID
) AS VentasPorCliente;
Lección 3.3: Subconsultas escalares en SELECT
Una subconsulta escalar devuelve un solo valor y puede usarse como una columna calculada.
-- Clientes con su última fecha de pedido
SELECT Nombre,
(SELECT MAX(FechaPedido) FROM Pedidos WHERE Pedidos.ClienteID = Clientes.ClienteID) AS UltimoPedido
FROM Clientes;
Lección 3.4: CTE (Common Table Expressions)
Las CTE crean consultas temporales con nombre que puedes reutilizar, mejorando la legibilidad.
-- CTE para calcular ventas mensuales
WITH VentasMensuales AS (
SELECT
YEAR(FechaPedido) AS Año,
MONTH(FechaPedido) AS Mes,
SUM(Total) AS TotalVentas
FROM Pedidos
GROUP BY YEAR(FechaPedido), MONTH(FechaPedido)
)
SELECT * FROM VentasMensuales
WHERE TotalVentas > 5000;
Ejercicios de Práctica del Módulo 3
Encuentra todos los productos cuyo precio es mayor que el precio promedio de su categoría.
Muestra los clientes que han gastado más que el promedio de todos los clientes.
Usa una CTE para calcular el ranking de vendedores por cantidad de ventas.
Encuentra los productos que se han vendido más que cualquier producto de la categoría
'Electrónicos'.
Crea una subconsulta para mostrar el cliente más reciente y sus detalles.
Módulo 4: Índices y Optimización de Rendimiento
Los índices son la clave para consultas rápidas en grandes volúmenes de datos. Aprende a crear y
mantenerlos eficientemente.
Lección 4.1: Conceptos de índices (clustered vs
non-clustered)
Los índices son como el índice de un libro. Clustered ordena físicamente los datos,
solo puede haber uno por tabla. Non-clustered crea una estructura separada para
búsquedas rápidas.
-- Ver índices existentes
SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID('Clientes');
Lección 4.2: Creación y administración de índices
Crea índices en columnas frecuentemente buscadas o unidas.
-- Índice non-clustered en la columna Email
CREATE INDEX IX_Clientes_Email ON Clientes(Email);
-- Índice compuesto en varias columnas
CREATE INDEX IX_Pedidos_ClienteFecha ON Pedidos(ClienteID, FechaPedido);
Lección 4.3: Análisis de planes de ejecución
Usa SET SHOWPLAN_ALL ON o el visualizador de SSMS para ver cómo SQL Server ejecuta tu
consulta y encontrar cuellos de botella.
-- Ver plan de ejecución sin ejecutar
SET SHOWPLAN_ALL ON
GO
SELECT * FROM Pedidos WHERE ClienteID = 123
GO
SET SHOWPLAN_ALL OFF
Lección 4.4: Buenas prácticas de optimización
Indexa columnas en cláusulas WHERE, JOIN y ORDER BY
Evita funciones en columnas indexadas en WHERE
Usa SELECT específico en lugar de SELECT *
Mantén las estadísticas actualizadas
Ejercicios de Práctica del Módulo 4
Crea un índice en la tabla Productos para optimizar búsquedas por nombre.
Analiza el plan de ejecución de una consulta grande y sugiere mejoras.
Crea un índice compuesto para optimizar la búsqueda de pedidos por cliente y fecha.
Investiga qué índices son más utilizados en tu base de datos.
Elimina índices redundantes que no se están usando.
Módulo 5: Procedimientos Almacenados y Funciones
Automatiza tareas complejas y encapsula lógica de negocio en objetos reutilizables y seguros.
Lección 5.1: Creación y ejecución de procedimientos
Los procedimientos almacenan consultas y lógica compleja que puedes ejecutar con un simple comando.
-- Crear procedimiento para obtener clientes activos
CREATE PROCEDURE sp_ObtenerClientesActivos
@FechaInicio DATE,
@FechaFin DATE
AS
BEGIN
SELECT * FROM Clientes
WHERE FechaUltimaCompra BETWEEN @FechaInicio AND @FechaFin;
END;
-- Ejecutar el procedimiento
EXEC sp_ObtenerClientesActivos '2024-01-01', '2024-12-31';
Lección 5.2: Parámetros de entrada y salida
Pasa valores a los procedimientos y recibe resultados calculados.
-- Procedimiento con parámetro de salida
CREATE PROCEDURE sp_CalcularTotalVentas
@ClienteID INT,
@TotalVentas DECIMAL(10,2) OUTPUT
AS
BEGIN
SELECT @TotalVentas = ISNULL(SUM(Total), 0)
FROM Pedidos
WHERE ClienteID = @ClienteID;
END;
-- Usar el procedimiento
DECLARE @Total DECIMAL(10,2);
EXEC sp_CalcularTotalVentas 123, @Total OUTPUT;
SELECT @Total AS TotalVentasCliente;
Lección 5.3: Funciones definidas por el usuario
Las funciones devuelven un valor y pueden usarse en SELECT, WHERE, etc.
-- Función para calcular descuento
CREATE FUNCTION fn_CalcularDescuento
(@Precio DECIMAL(10,2), @Porcentaje INT)
RETURNS DECIMAL(10,2)
AS
BEGIN
RETURN @Precio * (1 - @Porcentaje / 100.0);
END;
-- Usar la función
SELECT Producto, Precio, dbo.fn_CalcularDescuento(Precio, 15) AS PrecioConDescuento
FROM Productos;
Lección 5.4: Manejo de errores y transacciones
Asegura la integridad de los datos con TRY-CATCH y transacciones.
-- Procedimiento con manejo de errores
CREATE PROCEDURE sp_ProcesarPedido
@ClienteID INT,
@Total DECIMAL(10,2)
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
-- Validar cliente
IF NOT EXISTS (SELECT 1 FROM Clientes WHERE ClienteID = @ClienteID)
THROW 50001, 'Cliente no existe', 1;
-- Insertar pedido
INSERT INTO Pedidos(ClienteID, Total, Fecha) VALUES (@ClienteID, @Total, GETDATE());
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
THROW
END CATCH
END
Ejercicios de Práctica del Módulo 5
Crea un procedimiento que actualice el stock de productos después de una venta.
Crea una función que valide si un email tiene formato correcto.
Implementa un procedimiento que genere reportes mensuales de ventas.
Crea una función que calcule la edad a partir de la fecha de nacimiento.
Desarrolla un procedimiento con transacción para transferir fondos entre cuentas.