
Existe muchas confusiones sobre que es una expresión de tabla común (CTE), una subconsulta, una tabla temporal y una vista.
En este articulo profundizare en sus definiciones y en sus diferentes casos de uso con código de ejemplos.
Trabajaremos con una base de datos que incluye dos tablas: “Clientes” y “Ventas”. Nuestro objetivo es calcular las ventas totales por mes y filtrar aquellos productos cuyas ventas mensuales fueron inferiores a $1000.
𝑳𝒂 𝒕𝒂𝒃𝒍𝒂 𝒗𝒆𝒏𝒕𝒂𝒔 𝒕𝒊𝒆𝒏𝒆 𝒍𝒂𝒔 𝒔𝒊𝒈𝒖𝒊𝒆𝒏𝒕𝒆𝒔 𝒄𝒐𝒍𝒖𝒎𝒏𝒂𝒔:
CREATE TABLE dbo.Ventas(
ID int NULL,
Nombre_Cliente varchar(100) NULL,
Ciudad varchar(20) NULL,
MontoTotal decimal(18, 2) NULL,
Enero decimal(18, 2) NULL,
Febrero decimal(18, 2) NULL,
Marzo decimal(18, 2) NULL,
Abril decimal(18, 2) NULL,
Mayo decimal(18, 2) NULL,
Junio decimal(18, 2) NULL,
Julio decimal(18, 2) NULL,
Agosto decimal(18, 2) NULL,
Septiembre decimal(18, 2) NULL,
Octubre decimal(18, 2) NULL,
Noviembre decimal(18, 2) NULL,
Diciembre decimal(18, 2) NULL,
Producto varchar(20) NULL,
Fecha date NULL,
Categoria varchar(20) NULL,
Estado varchar(10) NULL,
Email varchar(100) NULL,
Telefono varchar(20) NULL
)
𝑳𝒂 𝒕𝒂𝒃𝒍𝒂 𝑪𝒍𝒊𝒆𝒏𝒕𝒆𝒔 𝒕𝒊𝒆𝒏𝒆 𝒍𝒂𝒔 𝒔𝒊𝒈𝒖𝒊𝒆𝒏𝒕𝒆𝒔 𝒄𝒐𝒍𝒖𝒎𝒏𝒂𝒔:
CREATE TABLE dbo.clientes(
ID int NULL,
Nombre varchar(20) NULL,
Ciudad varchar(20) NULL,
Edad int NULL
)
1️⃣𝐂𝐨𝐦𝐦𝐨𝐧 𝐓𝐚𝐛𝐥𝐞 𝐄𝐱𝐩𝐫𝐞𝐬𝐬𝐢𝐨𝐧 (𝐂𝐓𝐄)
CTE es un conjunto de resultados temporales al que puede hacer referencia dentro de una declaración SELECT, INSERT, UPDATE O DELETE.
Se define al inicio de la consulta mediante la WITH palabra clave.
Generalmente se utiliza para mejorar la legibilidad y dividir consultas complejas en partes pequeñas.
Los CTE son temporales y solo existe durante la ejecución de la consulta.
𝑬𝒋𝒆𝒎𝒑𝒍𝒐
WITH VentasMensuales AS (
SELECT
v.ID,
v.Nombre_Cliente,
v.Producto,
v.Enero + v.Febrero + v.Marzo + v.Abril + v.Mayo + v.Junio +
v.Julio + v.Agosto + v.Septiembre + v.Octubre + v.Noviembre + v.Diciembre AS TotalVentas
FROM ventas v
)
SELECT
c.ID AS ClienteID,
c.Nombre AS NombreCliente,
v.Producto,
v.TotalVentas
FROM VentasMensuales v
JOIN clientes c ON v.Nombre_Cliente = c.Nombre
WHERE v.TotalVentas < 1000;
🚀𝑬𝒙𝒑𝒍𝒊𝒄𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆𝒍 𝒄𝒐́𝒅𝒊𝒈𝒐
- VentasMensuales (CTE)
Calcula el total de ventas sumando todos los meses por producto
- Consulta principal.
Se UNE (JOIN) con la tabla Clientes para obtener información adicional del cliente. Se aplica filtro WHERE v.TotalVentas < 1000 para mostrar solo productos con ventas totales inferiores a 1000.
✅𝑽𝒆𝒏𝒕𝒂𝒋𝒂 𝒂𝒍 𝒖𝒔𝒂𝒓 𝑪𝑻𝑬 𝒆𝒏 𝒆𝒔𝒕𝒂 𝒄𝒐𝒏𝒔𝒖𝒍𝒕𝒂
- Código más limpio y legible: separamos el cálculo de Ventas totales en una estructura clara.
- Facilita la depuración y modificación: si necesitamos modificar el cálculo solo modificamos el CTE sin tocar la consulta principal.
- Optimización en bases de datos grandes: en algunos casos, los motores de base de datos optimizar mejor un CTE que una subconsulta anidad.
⚠️𝑳𝒊𝒎𝒊𝒕𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆 𝒖𝒔𝒂𝒓 𝑪𝑻𝑬 𝒆𝒏 𝒆𝒔𝒕𝒂 𝒄𝒐𝒏𝒔𝒖𝒍𝒕𝒂
- No mejora el rendimiento en consultas simples: En base de datos pequeñas, un CTE puede no ser más rápido, que una consulta con un JOIN directo a una subconsulta.
- No persiste los datos: Un CTE solo existe mientras la consulta se ejecuta; si necesitas usar varias veces la consulta puedes usar una tabla temporal o una vista.
- Puede consumir más memoria en consultas muy grandes: Si el CTE genera una gran cantidad de datos, puede ser más eficiente usar una tabla temporal.
2️⃣𝐒𝐮𝐛𝐜𝐨𝐧𝐬𝐮𝐥𝐭𝐚𝐬
Una subconsulta es una consulta dentro de otra consulta. Normalmente dentro de un SELECT Clausula, FROM y WHERE.
Se puede utilizar para filtrar o calcular un conjunto de resultados en función del resultado de otra consulta.
La subconsulta puede estar relacionadas (dependiendo de la consulta externa) o no correlacionadas (independientes de la consulta).
𝑬𝒋𝒆𝒎𝒑𝒍𝒐
SELECT
v.Nombre_Cliente,
v.Producto,
v.Fecha,
v.MontoTotal
FROM Ventas v
WHERE v.MontoTotal < 1000
AND v.Producto IN (
SELECT DISTINCT Producto
FROM Ventas
WHERE MontoTotal < 1000
);
🚀𝑬𝒙𝒑𝒍𝒊𝒄𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆𝒍 𝒄𝒐́𝒅𝒊𝒈𝒐
- Subconsulta interna: obtiene la lista de productos que tienen ventas totales menor a 1000.
- Consulta principal: Recupera todas las ventas que pertenecen a esos productos y filtra por ventas inferiores a 1000.
✅𝑽𝒆𝒏𝒕𝒂𝒋𝒂 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒔𝒖𝒃𝒄𝒐𝒏𝒔𝒖𝒍𝒕𝒂
Permite filtrar directamente dentro de la consulta WHERE sin necesidad de definir una estructura temporal. Puede anidarse dentro de la consulta.
⚠️𝑳𝒊𝒎𝒊𝒕𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒔𝒖𝒃𝒄𝒐𝒏𝒔𝒖𝒍𝒕𝒂
En grandes volúmenes de datos, el rendimiento puede verse afectado, ya que la Consulta se ejecuta repetidamente por cada fila de la consulta principal.
3️⃣𝐓𝐚𝐛𝐥𝐚 𝐭𝐞𝐦𝐩𝐨𝐫𝐚𝐥
Es una tabla que existe temporalmente y se almacena en Base de Datos mientras dura la sesión de la ejecución.
Puede crear una tabla temporal para almacenar resultados y utilizar en consultas posteriores.
Las tablas temporales son útiles para almacenar datos que deben utilizarse en múltiples consultas.
𝑬𝒋𝒆𝒎𝒑𝒍𝒐
-- Paso 1: Crear la tabla temporal
CREATE TABLE #VentasFiltradas (
Nombre_Cliente NVARCHAR(255),
Producto NVARCHAR(255),
Fecha DATE,
MontoTotal DECIMAL(18,2)
);
-- Paso 2: Insertar datos en la tabla temporal
INSERT INTO #VentasFiltradas (Nombre_Cliente, Producto, Fecha, MontoTotal)
SELECT Nombre_Cliente, Producto, Fecha, MontoTotal
FROM Ventas
WHERE MontoTotal < 1000;
-- Paso 3: Consultar desde la tabla temporal
SELECT * FROM #VentasFiltradas;
-- Paso 4: Eliminar la tabla temporal después de su uso
DROP TABLE #VentasFiltradas;
🚀𝑬𝒙𝒑𝒍𝒊𝒄𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆𝒍 𝒄𝒐́𝒅𝒊𝒈𝒐
- Creamos una tabla temporal #VentasFiltradas con las columnas y el tipo de dato.
- Insertamos a la tabla temporal, los datos filtrados de Ventas, es decir solo los productos con ventas menores a $1000.
- Consultamos la tabla temporal para analizar los datos.
- Eliminamos la tabla temporal una vez terminada la consulta para liberar espacio en la base de datos.
✅𝑽𝒆𝒏𝒕𝒂𝒋𝒂𝒔 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒖𝒏𝒂 𝒕𝒂𝒃𝒍𝒂 𝒕𝒆𝒎𝒑𝒐𝒓𝒂𝒍
Mejora el rendimiento en consultas complejas:🚀Almacenar datos intermedios en una tabla temporal evita la repetición de cálculos pesados en una consulta.
Facilita la manipulación de datos temporales:🔄Puedes modificar, agregar o eliminar datos sin afectar las tablas originales.
Reutilización en múltiples consultas:🔁A diferencia de un CTE o una subconsulta, una tabla temporal puede usarse varias veces dentro de la misma sesión
⚠️𝑳𝒊𝒎𝒊𝒕𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒕𝒂𝒃𝒍𝒂 𝒕𝒆𝒎𝒑𝒐𝒓𝒂𝒍
Consumen memoria en tempdb
: 🖥️Las tablas temporales se almacenan en la base de datos tempdb
, lo que puede afectar el rendimiento si se usan en exceso.
Son temporales y se eliminan al finalizar la sesión: ⏳No pueden reutilizarse en diferentes sesiones o conexiones, a menos que sean tablas temporales globales (##TablaTemporal
)
4️⃣𝐕𝐢𝐬𝐭𝐚𝐬
Una vista es una tabla virtual creada mediante una consulta. No almacena datos, sino que guarda código de una consulta empaquetada, que representa datos de una o más tablas en función de una consulta.
A diferencia de las CTE o subconsultas, las vistas son persistentes y pueden realizarse en diferentes sesiones y consultas.
Las vistas proporcionan una capa de abstracción y pueden simplificar consultas complejas al crear lógica reutilizable.
𝑬𝒋𝒆𝒎𝒑𝒍𝒐
CREATE VIEW VentasFiltradas AS
SELECT
Nombre_Cliente,
Producto,
Fecha,
MontoTotal
FROM Ventas
WHERE MontoTotal < 1000;
-- Paso 2: Consultar la vista
SELECT * FROM VentasFiltradas;
🚀𝑬𝒙𝒑𝒍𝒊𝒄𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆𝒍 𝒄𝒐́𝒅𝒊𝒈𝒐
- Creamos una vista ventasfiltradas que almacena la consulta con las ventas menores a 1000.
- Consultamos la vista como si fuera una tabla normal (Select * from ventasfiltradas).
✅𝑽𝒆𝒏𝒕𝒂𝒋𝒂𝒔 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒖𝒏𝒂 𝒗𝒊𝒔𝒕𝒂
Reutilización: se puede usar en múltiples consultas, sin necesidad de escribir más lógica.
Simplicidad: Hace que las consultas sean más limpias y fáciles de leer.
Seguridad: Puede usarse para restringir el acceso a ciertos datos de la tabla original. Lo cual es el método mas usado en las empresas cuando se solicita acceso a ver esos datos.
⚠️𝑳𝒊𝒎𝒊𝒕𝒂𝒄𝒊𝒐́𝒏 𝒅𝒆 𝒖𝒔𝒂𝒓 𝒖𝒏𝒂 𝒗𝒊𝒔𝒕𝒂
Las vistas no son adecuadas para operaciones complejas a gran escala donde los datos deben modificarse con frecuencia.
🔍𝑫𝒊𝒇𝒆𝒓𝒆𝒏𝒄𝒊𝒂𝒔 𝒄𝒍𝒂𝒗𝒆

🎯𝑬𝒋𝒆𝒓𝒄𝒊𝒐𝒔 𝒓𝒆𝒍𝒂𝒄𝒊𝒐𝒏𝒂𝒅𝒐 𝒂 𝑪𝑻𝑬
Descripción: Un negocio quiere identificar clientes que han realiza mas de 5 compras en el último año.
WITH ClientesFrecuentes AS (
SELECT
ID,
Nombre_Cliente,
COUNT(*) AS TotalCompras
FROM Ventas
WHERE Fecha >= DATEADD(YEAR, -1, GETDATE())
GROUP BY ID, Nombre_Cliente
HAVING COUNT(*) > 5
)
SELECT * FROM ClientesFrecuentes;
🎯𝑬𝒋𝒆𝒓𝒄𝒊𝒐 𝒓𝒆𝒍𝒂𝒄𝒊𝒐𝒏𝒂𝒅𝒐 𝒂 𝑺𝒖𝒃𝒄𝒐𝒏𝒔𝒖𝒍𝒕𝒂
Descripción: Analizar qué productos generan más del 10% de las ventas totales en los últimos 6 meses.
SELECT Producto, SUM(MontoTotal) AS TotalVentas
FROM Ventas
WHERE Fecha >= DATEADD(MONTH, -6, GETDATE())
GROUP BY Producto
HAVING SUM(MontoTotal) > (
SELECT SUM(MontoTotal) * 0.10 FROM Ventas WHERE Fecha >= DATEADD(MONTH, -6, GETDATE())
);
🎯𝑬𝒋𝒆𝒎𝒑𝒍𝒐 𝒓𝒆𝒍𝒂𝒄𝒊𝒐𝒏𝒂𝒅𝒐 𝒂 𝑻𝒂𝒃𝒍𝒂 𝑻𝒆𝒎𝒑𝒐𝒓𝒂𝒍
CREATE TABLE #ClientesRetenidos (
Nombre_Cliente NVARCHAR(255),
TotalMesesComprados INT
);
INSERT INTO #ClientesRetenidos
SELECT Nombre_Cliente, COUNT(DISTINCT MONTH(Fecha)) AS TotalMesesComprados
FROM Ventas
WHERE Fecha >= DATEADD(YEAR, -1, GETDATE())
GROUP BY Nombre_Cliente
HAVING COUNT(DISTINCT MONTH(Fecha)) >= 3;
SELECT * FROM #ClientesRetenidos;
DROP TABLE #ClientesRetenidos;
🎯𝑬𝒋𝒆𝒓𝒄𝒊𝒐 𝒓𝒆𝒍𝒂𝒄𝒊𝒐𝒏𝒂𝒅𝒐 𝒂 𝒖𝒏𝒂 𝑽𝒊𝒔𝒕𝒂
Descripción: Un gerente de ventas necesita un informe recurrente sobre las ventas de cada categoría de productos.
CREATE VIEW VentasPorCategoria AS
SELECT Categoria, SUM(MontoTotal) AS TotalVentas
FROM Ventas
GROUP BY Categoria;
-- Consultar la vista
SELECT * FROM VentasPorCategoria;
📌𝐂𝐨𝐧𝐜𝐥𝐮𝐬𝐢𝐨́𝐧
✅ CTE → Para dividir consultas complejas en partes legibles.
✅ Subconsultas → Cuando se necesita filtrar datos en una única consulta.
✅ Tablas Temporales → Para almacenar datos intermedios dentro de una sesión.
✅ Vistas → Para consultas recurrentes y optimización de acceso a datos.