Contenido de esta guía
Respuesta rápida
INSERT INTO ... SELECT inserta en una tabla las filas que devuelve una consulta. En lugar de escribir cada fila con VALUES, usas un SELECT como fuente para copiar, filtrar, transformar o resumir datos antes de insertarlos.
La lista de columnas destino y la salida del SELECT deben corresponder en cantidad y significado. Las restricciones de la tabla destino siguen aplicándose a cada fila insertada.
Cuándo usar INSERT ... SELECT
Este patrón es útil cuando las filas nuevas ya existen, total o parcialmente, en otras tablas. Algunos casos habituales son crear una tabla de trabajo, archivar un subconjunto, migrar datos a una estructura nueva o cargar un resumen calculado.
| Forma | Conviene cuando… |
|---|---|
INSERT ... VALUES | conoces explícitamente los valores que vas a insertar |
INSERT ... SELECT | las filas proceden de una consulta y pueden filtrarse o transformarse |
Sintaxis segura
INSERT INTO tabla_destino (columna_a, columna_b)
SELECT expresion_a, expresion_b
FROM tabla_origen
WHERE condicion;Lee ambas listas en paralelo: la primera expresión del SELECT alimenta la primera columna destino, la segunda expresión alimenta la segunda y así sucesivamente. Escribir la lista destino evita depender del orden físico de las columnas de la tabla.
El SELECT decide qué se intenta insertar; la tabla destino decide qué es válido. Una clave duplicada, un NOT NULL, una FOREIGN KEY o un CHECK pueden rechazar filas aunque la consulta de origen sea correcta.
Ejemplo: copiar clientes de Madrid
Supongamos que ya existe una tabla de trabajo con tres columnas compatibles:
CREATE TABLE clientes_madrid (
id INTEGER PRIMARY KEY,
nombre TEXT NOT NULL,
ciudad TEXT NOT NULL
);Podemos llenarla a partir de clientes sin repetir manualmente los valores:
INSERT INTO clientes_madrid (id, nombre, ciudad)
SELECT id, nombre, ciudad
FROM clientes
WHERE ciudad = 'Madrid';| id | nombre | ciudad |
|---|---|---|
| 1 | Ana Torres | Madrid |
| 3 | Marta Ruiz | Madrid |
| 6 | Pablo Sanz | Madrid |
| 9 | Noa Vidal | Madrid |
La consulta fuente devuelve cuatro filas y esas cuatro filas se insertan. Si el WHERE no devolviera ninguna, la sentencia insertaría cero filas.
También puedes transformar antes de insertar
Las expresiones del SELECT no tienen que ser copias literales de columnas. Puedes calcular valores, usar CASE, aplicar funciones o combinar tablas, siempre que la salida siga siendo compatible con el destino.
INSERT INTO clientes_resumen (cliente_id, nombre, estado)
SELECT id,
nombre,
CASE WHEN activo = 1 THEN 'activo' ELSE 'inactivo' END
FROM clientes;Esta forma separa dos responsabilidades: el SELECT construye las filas y el INSERT las guarda en el esquema destino.
Comprueba el SELECT antes de modificar datos
Una práctica segura es ejecutar primero únicamente la consulta fuente. Comprueba cantidad de filas, columnas, valores y duplicados. Después ejecuta el INSERT dentro de una transacción cuando el entorno y el motor lo permitan.
-- 1. Comprueba exactamente qué filas produce la fuente
SELECT id, nombre, ciudad
FROM clientes
WHERE ciudad = 'Madrid';
-- 2. Inserta solo después de validar esa salida
INSERT INTO clientes_madrid (id, nombre, ciudad)
SELECT id, nombre, ciudad
FROM clientes
WHERE ciudad = 'Madrid';No confundas el orden de presentación con el almacenamiento. Si después necesitas leer las filas en un orden concreto, utiliza ORDER BY en el SELECT que consulta la tabla destino.
Errores frecuentes
Intercambiar el significado de las columnas
INSERT INTO clientes_madrid (id, nombre, ciudad)
SELECT id, ciudad, nombre
FROM clientes;La cantidad de expresiones coincide, pero nombre y ciudad quedaron invertidos. SQL no puede deducir la intención por el nombre de las columnas.
Olvidar que las restricciones siguen activas
Si la tabla destino ya contiene un id que el SELECT intenta volver a insertar, una clave primaria o restricción única puede rechazar la operación. Revisa duplicados antes de cargar.
Usar INSERT ... SELECT cuando solo necesitas consultar
Una copia persistente crea mantenimiento adicional. Si solo necesitas reutilizar temporalmente un resultado, una CTE, una subconsulta o una vista puede expresar mejor la intención.
Práctica guiada
Copia productos disponibles y asequibles
Parte de una tabla vacía productos_disponibles(id, nombre, precio). Inserta productos cuyo stock sea mayor que 0 y cuyo precio sea menor que 100.
Criterio de éxito: se insertan Ratón, Teclado, Auriculares, Disco SSD y Cable USB-C.
productos.SELECT debe devolver exactamente id, nombre y precio.stock > 0 y precio < 100 con AND.Solución razonada
INSERT INTO productos_disponibles (id, nombre, precio)
SELECT id, nombre, precio
FROM productos
WHERE stock > 0
AND precio < 100;La consulta fuente selecciona cinco productos. Cada fila conserva el mismo identificador, nombre y precio al pasar a la tabla destino.
Compatibilidad entre motores
PostgreSQL y SQLite permiten usar una consulta como fuente de INSERT. La sintaxis básica INSERT INTO tabla (columnas) SELECT ... es ampliamente reconocible, pero mecanismos de conflicto, identidad, RETURNING y detalles transaccionales varían entre motores.
El motor educativo de AprenderSQL.es cubre las operaciones de modificación necesarias para el curso, pero no se utiliza como prueba definitiva de todas las variantes de INSERT ... SELECT. Los ejemplos de esta página se comprobaron con SQLite real sobre la misma base educativa.
Qué debes recordar
INSERT ... SELECTguarda las filas producidas por una consulta.- La lista destino y la salida del
SELECTdeben corresponder en cantidad y significado. - Las restricciones de la tabla destino siguen aplicándose.
- Comprueba primero el
SELECTantes de modificar datos. - Una consulta que devuelve cero filas provoca cero inserciones.