Tablas temporales

Una tabla temporal es una tabla que solo existe durante la sesión actual de MySQL. Se crea con CREATE TEMPORARY TABLE y se destruye automáticamente cuando la conexión se cierra. Otras sesiones no pueden ver ni acceder a tus tablas temporales, lo que las hace ideales para almacenar resultados intermedios durante cálculos complejos.

Sintaxis

CREATE TEMPORARY TABLE nombre_tabla (
    columna1 tipo_de_dato,
    columna2 tipo_de_dato,
    ...
);

La sintaxis es idéntica a CREATE TABLE, con la única diferencia de la palabra TEMPORARY.

Crear una tabla temporal

CREATE TEMPORARY TABLE resumen_ventas (
    categoria VARCHAR(100),
    total_productos INT,
    ingresos DECIMAL(12, 2)
);
Query OK, 0 rows affected (0.00 sec)

La creación es instantánea porque las tablas temporales se almacenan en memoria o en archivos temporales del sistema, no en el directorio de datos permanente de MySQL.

Puedes insertar datos y consultarla como cualquier otra tabla:

INSERT INTO resumen_ventas
SELECT
    c.nombre AS categoria,
    COUNT(DISTINCT dp.producto_id) AS total_productos,
    SUM(dp.cantidad * dp.precio_unitario) AS ingresos
FROM categorias c
JOIN productos p ON p.categoria_id = c.id
JOIN detalle_pedidos dp ON dp.producto_id = p.id
GROUP BY c.nombre;
 
SELECT * FROM resumen_ventas ORDER BY ingresos DESC;
categoriatotal_productosingresos
Portátiles34948.00
Smartphones32098.98
Accesorios electrónicos2189.95
Running1259.98
Cocina2289.98
Muebles2798.00
Fitness3269.97
Programación2149.96
Novelas357.96
Camisetas284.97
Pantalones2169.97

Crear desde un SELECT

La forma más habitual de crear tablas temporales es a partir de una consulta:

CREATE TEMPORARY TABLE clientes_vip AS
SELECT
    c.id,
    c.nombre,
    c.apellidos,
    COUNT(p.id) AS total_pedidos,
    SUM(p.total) AS gasto_total
FROM clientes c
JOIN pedidos p ON c.id = p.cliente_id
GROUP BY c.id, c.nombre, c.apellidos
HAVING gasto_total > 500;

Ahora puedes usar clientes_vip en consultas posteriores sin repetir la subconsulta compleja:

SELECT nombre, apellidos, total_pedidos, gasto_total
FROM clientes_vip
ORDER BY gasto_total DESC;
nombreapellidostotal_pedidosgasto_total
PedroFernández Castro21979.97
MaríaGarcía López31849.95
CarmenRuiz Jiménez11399.00
CarlosRodríguez Martín21029.98
AndrésVega Romero1699.00
DavidSánchez Moreno2509.97

Visibilidad entre sesiones

Las tablas temporales son privadas de cada sesión. Si dos usuarios se conectan simultáneamente y ambos crean una tabla temporal con el mismo nombre, cada uno tiene su propia copia independiente:

-- Sesión 1
CREATE TEMPORARY TABLE datos (valor INT);
INSERT INTO datos VALUES (100);
 
-- Sesión 2 (al mismo tiempo)
CREATE TEMPORARY TABLE datos (valor INT);
INSERT INTO datos VALUES (200);
 
-- Cada sesión ve solo sus propios datos

Esta privacidad elimina la necesidad de coordinar nombres entre sesiones o preocuparse por conflictos.

Tabla temporal con el mismo nombre que una permanente

Si creas una tabla temporal con el mismo nombre que una tabla permanente, la tabla temporal "oculta" la permanente durante tu sesión:

-- La tabla permanente 'productos' tiene 30 filas
SELECT COUNT(*) FROM productos;  -- Resultado: 30
 
CREATE TEMPORARY TABLE productos (
    id INT PRIMARY KEY,
    nombre VARCHAR(100)
);
 
INSERT INTO productos VALUES (1, 'Producto temporal');
 
-- Ahora accedemos a la tabla temporal
SELECT COUNT(*) FROM productos;  -- Resultado: 1
 
-- Al eliminar la temporal, reaparece la permanente
DROP TEMPORARY TABLE productos;
SELECT COUNT(*) FROM productos;  -- Resultado: 30

Aunque esta capacidad existe, no es una práctica recomendable. Usar el mismo nombre causa confusión y errores difíciles de diagnosticar. Nombra las tablas temporales con un prefijo descriptivo como tmp_ o un nombre claramente diferente.

Operaciones con tablas temporales

Las tablas temporales soportan las mismas operaciones que las permanentes: INSERT, UPDATE, DELETE, SELECT con JOINs, índices, ALTER TABLE, etc.

-- Añadir un índice para mejorar consultas
ALTER TABLE clientes_vip ADD INDEX idx_gasto (gasto_total);
 
-- Actualizar datos
UPDATE clientes_vip SET gasto_total = gasto_total * 1.1 WHERE total_pedidos > 2;
 
-- Usar en JOINs
SELECT cv.nombre, cv.gasto_total, p.id AS ultimo_pedido
FROM clientes_vip cv
JOIN pedidos p ON cv.id = p.cliente_id
WHERE p.fecha_pedido = (
    SELECT MAX(fecha_pedido)
    FROM pedidos
    WHERE cliente_id = cv.id
);

Tablas temporales y transacciones

Las tablas temporales creadas con InnoDB (el motor por defecto) participan en transacciones:

CREATE TEMPORARY TABLE temp_calculo (id INT, valor DECIMAL(10,2));
 
START TRANSACTION;
INSERT INTO temp_calculo VALUES (1, 100.00);
INSERT INTO temp_calculo VALUES (2, 200.00);
ROLLBACK;
 
SELECT * FROM temp_calculo;
Empty set (0.00 sec)

El ROLLBACK deshace las inserciones, pero la tabla temporal sigue existiendo (vacía). Las operaciones DDL (CREATE TEMPORARY TABLE, DROP TEMPORARY TABLE) no se pueden deshacer con rollback.

Eliminar tablas temporales

Las tablas temporales se eliminan automáticamente al cerrar la sesión. Si necesitas eliminarla antes:

DROP TEMPORARY TABLE resumen_ventas;

Usa DROP TEMPORARY TABLE en lugar de DROP TABLE. La palabra TEMPORARY es importante: garantiza que solo se elimina una tabla temporal. Si usas DROP TABLE y no existe una tabla temporal con ese nombre, MySQL eliminaría la tabla permanente (si existe), lo que podría ser catastrófico.

-- Seguro: solo elimina la tabla temporal
DROP TEMPORARY TABLE IF EXISTS datos_temp;
 
-- Peligroso: podría eliminar una tabla permanente
DROP TABLE IF EXISTS datos_temp;

Casos de uso

El caso más común es simplificar consultas complejas. En lugar de escribir una consulta enorme con múltiples subconsultas anidadas, puedes dividirla en pasos:

-- Paso 1: Calcular métricas por empleado
CREATE TEMPORARY TABLE tmp_metricas_empleado AS
SELECT
    e.id,
    e.nombre,
    e.apellidos,
    COUNT(p.id) AS pedidos_gestionados,
    COALESCE(SUM(p.total), 0) AS ingresos_generados
FROM empleados e
LEFT JOIN pedidos p ON e.id = p.empleado_id
GROUP BY e.id, e.nombre, e.apellidos;
 
-- Paso 2: Comparar con la media
SELECT
    nombre,
    apellidos,
    pedidos_gestionados,
    ingresos_generados,
    ROUND(ingresos_generados / NULLIF(pedidos_gestionados, 0), 2) AS ticket_medio
FROM tmp_metricas_empleado
WHERE pedidos_gestionados > 0
ORDER BY ingresos_generados DESC;
nombreapellidospedidos_gestionadosingresos_generadosticket_medio
NataliaHerrera López106422.89642.29
DanielVargas Martín83148.88393.61
PatriciaCano Sánchez71753.88250.55

Otro caso habitual es crear tablas temporales para reportes que requieren múltiples pasadas sobre los datos, o para almacenar parámetros de configuración durante procedimientos almacenados complejos.

Limitaciones

Las tablas temporales no pueden ser referenciadas por claves foráneas de otras tablas. No puedes referenciar la misma tabla temporal más de una vez en la misma consulta:

CREATE TEMPORARY TABLE tmp_numeros (n INT);
INSERT INTO tmp_numeros VALUES (1), (2), (3);
 
-- Esto falla en MySQL
SELECT a.n, b.n
FROM tmp_numeros a
JOIN tmp_numeros b ON a.n < b.n;
ERROR 1137 (HY000): Can't reopen table: 'a'

La solución es crear una segunda tabla temporal con los mismos datos, o usar una CTE:

WITH numeros AS (SELECT n FROM tmp_numeros)
SELECT a.n, b.n
FROM tmp_numeros a
JOIN numeros b ON a.n < b.n;

Las tablas temporales tampoco aparecen en SHOW TABLES ni en information_schema.TABLES, lo que dificulta su inspección.

Limpieza

DROP TEMPORARY TABLE IF EXISTS resumen_ventas;
DROP TEMPORARY TABLE IF EXISTS clientes_vip;
DROP TEMPORARY TABLE IF EXISTS temp_calculo;
DROP TEMPORARY TABLE IF EXISTS tmp_metricas_empleado;
DROP TEMPORARY TABLE IF EXISTS tmp_numeros;

Con esto completamos la sección de definición de tablas. En la siguiente sección exploraremos las restricciones: NOT NULL, PRIMARY KEY, FOREIGN KEY, UNIQUE, DEFAULT, CHECK y AUTO_INCREMENT.

Escrito por Eduardo Lázaro