2011-11-28 18 views
15

righe Come fai a inserto selezionata da table_source a table_target utilizzando SQL in MySQL dove:INSERT INTO ... SELECT senza entrare in dettaglio tutte le colonne

  • Entrambe le tabelle hanno lo stesso schema
  • Tutte le colonne devono trasferire ad eccezione l'incremento automatico id
  • Senza scrivere esplicitamente tutti i nomi delle colonne, come sarebbe noioso

il banale INSERT INTO table_target SELECT * FROM table_source non riesce su voci duplicate per chiave primaria.

risposta

11

O di elencare tutti i campi desiderati nell'inserto ... selezionare, o si usa qualcos'altro esternamente per costruire la lista per te.

SQL non ha qualcosa come SELECT * except somefield FROM, quindi dovrai mordere il proiettile e scrivere i nomi dei campi.

+2

Sei giusto, alla fine ho usato la sintassi esplicita. Per completezza: ottenere facilmente la lista colonne usando ['DESCRIBE'] (http://dev.mysql.com/doc/refman/5.0/en/describe.html) e quindi usare la sintassi' INSERT INTO table1 (campo1, campo2 , campo3) SELECT table2.field1, table2.field2, table2.field3 FROM table2; ' – Jonathan

+0

Il modo più semplice per ottenere i nomi dei campi csv: ' SELECT CONCAT (GROUP_CONCAT (COLUMN_NAME SEPARATOR ','), "\ n") FROM INFORMATION_SCHEMA .COLONNI WHERE TABLE_SCHEMA = 'dbname' AND TABLE_NAME = 'tablename' GROUP BY TABLE_NAME' – Hafenkranich

2

Naturalmente, la chiave primaria deve essere unica. Dipende da ciò che si desidera raggiungere, ma è possibile escludere righe con una chiave primaria già esistente.

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

UPDATE: dal momento che è necessario anche le righe in più, si dovrebbe risolvere il conflitto prima, vuol table_source hanno rapporti? Se non si poteva cambiare quelle chiavi:

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

Dove 1000, è una costante, abbastanza grande in modo da andare dopo la fine della vostra tavola.

+0

ho bisogno di quelle righe troppo ... – Jonathan

+0

ok, aggiornata la risposta – stivlo

+0

che è una buona soluzione solo se non si dispone di chiavi esterne che puntano a 'table_source'. Inoltre, se ci fosse un modo per recuperare in modo dinamico l'ID più grande in "table_target' invece di usare una costante, sarebbe una soluzione leggermente migliore – Jonathan

15

I nomi delle colonne devono essere specificate -

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

basta passare NULL come un valore per il campo id incremento automatico.

+0

Grazie! Questo ha aiutato. – Hafenkranich

0

INSERT IGNORE solo "ignorare" le righe duplicate.

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

+0

Non sarebbe ... orribile ?! – Jonathan

+0

No, se le righe ignorate sono le righe necessarie. in caso contrario, è possibile eliminare per ID (o altro campo unico) e "INSERIRE". –

3

noioso, ma sicuro e corretto.

La scrittura di istruzioni INSERT senza fornire un elenco di colonne conduce a un codice difficile da eseguire il debug e, soprattutto, codice molto fragile che si interromperà se viene modificata la definizione della tabella.

Se non è possibile scrivere i nomi delle colonne da soli, è relativamente facile creare uno strumento nel codice che creerà per voi l'elenco separato da virgole.

0

Probabilmente puoi farlo con istruzioni preparate.

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

Sembra che le colonne non possano essere fornite come segnaposto in una dichiarazione preparata MySQL. Ho compilato la seguente soluzione per il test:

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

Questa è la mia soluzione finale per l'aggiornamento di massa con il comando 'sostituire inserto'.

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; 
Problemi correlati