Modificar datos · copiar desde una consulta

INSERT INTO ... SELECT

Inserta el resultado de un SELECT en otra tabla sin repetir manualmente cada fila y conservando el control sobre columnas y restricciones.

Lectura: 9–11 minEjemplo comprobadoPráctica con pistas
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.

VALUES frente a SELECT como fuente
FormaConviene cuando…
INSERT ... VALUESconoces explícitamente los valores que vas a insertar
INSERT ... SELECTlas filas proceden de una consulta y pueden filtrarse o transformarse

Sintaxis segura

SQL
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:

Tabla destino de práctica
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:

SQL comprobado en SQLite
INSERT INTO clientes_madrid (id, nombre, ciudad)
SELECT id, nombre, ciudad
FROM clientes
WHERE ciudad = 'Madrid';
Contenido comprobado de clientes_madrid
idnombreciudad
1Ana TorresMadrid
3Marta RuizMadrid
6Pablo SanzMadrid
9Noa VidalMadrid

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.

Ejemplo conceptual
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.

Secuencia de verificación
-- 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

Riesgo
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

Intermedia · modificación de datos

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.

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 ... SELECT guarda las filas producidas por una consulta.
  • La lista destino y la salida del SELECT deben corresponder en cantidad y significado.
  • Las restricciones de la tabla destino siguen aplicándose.
  • Comprueba primero el SELECT antes de modificar datos.
  • Una consulta que devuelve cero filas provoca cero inserciones.

Conceptos relacionados

Fuentes técnicas consultadas