2011-11-28 22 views
15

filas ¿Cómo inserto seleccionado de table_source a table_target utilizando SQL en MySQL donde:INSERT INTO ... SELECT sin detallar todas las columnas

  • Ambas tablas tienen el mismo esquema
  • Todas las columnas deben transferir a excepción de el incremento automático id
  • Sin escribir de forma explícita todos los nombres de columna, ya que sería tedioso

el trivial INSERT INTO table_target SELECT * FROM table_source falla en las entradas duplicadas para la clave principal.

Respuesta

11

O usted enumera todos los campos que desee en el inserto ... selectas, o bien utilizar algo más externo para construir la lista para ti.

SQL no tiene algo como SELECT * except somefield FROM, por lo que tendrá que morder la viñeta y escribir los nombres de los campos.

+2

Estás bien, al final utilicé la sintaxis explícita. Para completar: obtenga fácilmente la lista de columnas usando ['DESCRIBE'] (http://dev.mysql.com/doc/refman/5.0/en/describe.html) y luego use la sintaxis' INSERT INTO table1 (field1, field2 , campo3) SELECCIONE table2.field1, table2.field2, table2.field3 FROM table2; ' – Jonathan

+0

La forma más fácil de obtener los nombres de los campos csv: ' SELECCIONE CONCAT (GROUP_CONCAT (COLUMN_NAME SEPARATOR ','), "\ n") FROM INFORMATION_SCHEMA .COLUMNAS DONDE TABLE_SCHEMA = 'dbname' Y TABLE_NAME = 'tablename' GRUPO POR TABLE_NAME' – Hafenkranich

2

Por supuesto, la clave principal debe ser única. Depende de lo que desee lograr, pero podría excluir filas con una clave principal que ya existe.

INSERT INTO table_target SELECT * FROM table_source 
WHERE table_source.id NOT IN (SELECT id FROM table_target) 

ACTUALIZACIÓN: puesto que también necesita las filas adicionales, que debe resolver el conflicto en primer lugar, qué table_source tienen relaciones? Si no se podía cambiar esas claves:

UPDATE table_source SET id = id + 1000 
WHERE id IN (SELECT id FROM table_target) 

Dónde 1000, es una constante, lo suficientemente grande como para que vayan después del final de la tabla.

+0

necesito esas filas también ... – Jonathan

+0

bien, la respuesta actualizada – stivlo

+0

Esa es una buena solución sólo si no tiene las claves externas que apuntan a 'table_source'. Además, si pudiera haber una forma de obtener dinámicamente el ID más grande en 'table_target' en lugar de usar una constante, sería una solución ligeramente mejor – Jonathan

15

nombres de las columnas tienen que ser especificados -

INSERT INTO table_target SELECT NULL, column_name1, column_name2, column_name3, ... 
    FROM table_source; 

sólo tiene que pasar NULL como un valor para el campo ID de incremento automático.

+0

¡Gracias! Eso ayudó. – Hafenkranich

0

INSERT IGNORE simplemente "omitir" las filas duplicadas.

http://dev.mysql.com/doc/refman/5.5/en/insert.html

+0

¿No sería eso ... horrible? – Jonathan

+0

No, si las filas ignoradas son las filas que necesita. de lo contrario, puede eliminar por ID (u otro campo único) e "INSERTAR". –

3

tedioso, pero segura y correcta.

Escribir las declaraciones INSERT sin proporcionar una lista de columnas conduce a un código que es difícil de depurar y, más importante aún, un código muy frágil que se romperá si se cambia la definición de la tabla.

Si no puede escribir los nombres de las columnas usted mismo, entonces es relativamente fácil crear una herramienta en su código que creará la lista separada por comas.

0

Probablemente pueda hacerlo con declaraciones preparadas.

PREPARE table_target_insert FROM 'INSERT INTO table_target SELECT ? FROM table_source'; 
SET @cols:=''; 
SELECT @cols:=GROUP_CONCAT(IF(column_name = 'id','NULL',column_name) separator ",") FROM information_schema.columns WHERE table_name='table_source'; 
EXECUTE table_target_insert USING @cols; 
0

Parece que las columnas no se pueden dar como un marcador de posición en una declaración preparada de MySQL. He compilado la siguiente solución para la prueba:

SET @schema_db = 'DB'; 
SET @table = 'table'; 
SET @cols = (SELECT CONCAT(GROUP_CONCAT(COLUMN_NAME SEPARATOR ', '), "\n") FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @table GROUP BY TABLE_NAME); 
SET @Querystr = CONCAT('SELECT',' ', @cols,' ','FROM',' ',@schema_db,'.',@table,' ', 'Limit 5'); 
PREPARE stmt FROM @Querystr; 
EXECUTE stmt; 
1

Esta es mi solución final para la actualización masiva con el mandato de reemplazar a insertar '.

SET @@session.group_concat_max_len = @@global.max_allowed_packet; 
SET @schema_db = 'db'; 
SET @tabl = 'table'; 
SET @cols = (SELECT CONCAT('`',GROUP_CONCAT(COLUMN_NAME SEPARATOR '`, `'), '`') FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = @schema_db AND TABLE_NAME = @tabl GROUP BY TABLE_NAME); 
SET @Querystr = CONCAT('REPLACE INTO ',@schema_db,'.',@tabl,' SELECT ', @cols,' FROM import.tbl_', @tabl); 

PREPARE stmt FROM @Querystr; 
EXECUTE stmt; 
Cuestiones relacionadas