2009-04-08 21 views
75

Ho cercato un po 'di tempo ma non riesco a trovare una soluzione facile per il mio problema. Vorrei duplicare un record in una tabella, ma ovviamente, la chiave primaria univoca deve essere aggiornata.Duplicare/copiare i record nella stessa tabella MySQL

ho questa query:

INSERT INTO invoices 
    SELECT * FROM invoices AS iv WHERE iv.ID=XXXXX 
    ON DUPLICATE KEY UPDATE ID = (SELECT MAX(ID)+1 FROM invoices) 

il problema è che questo cambia solo il ID della fila invece di copiare la fila. Qualcuno sa come risolvere questo?

// modifica: Mi piacerebbe farlo senza digitare tutti i nomi dei campi perché i nomi dei campi possono cambiare nel tempo.

risposta

115

Il modo in cui di solito lo utilizzo è utilizzando una tabella temporanea. Probabilmente non è efficiente dal punto di vista computazionale ma sembra funzionare bene! Qui sto duplicando il record 99 nella sua interezza, creando il record 100.

CREATE TEMPORARY TABLE tmp SELECT * FROM invoices WHERE id = 99; 

UPDATE tmp SET id=100 WHERE id = 99; 

INSERT INTO invoices SELECT * FROM tmp WHERE id = 100; 

Spero che funzioni per te!

+0

Mi piace, un passo nel mezzo per tenere d'occhio le cose – SeanDowney

+3

Se si sta copiando un singolo record è possibile rilasciare il punto in entrambi gli aggiornamenti e inserire. Quindi potresti semplicemente premere due volte nella console mysql per visualizzare l'ultima operazione della cronologia, modificare l'id nell'aggiornamento che è comodo alla fine, premere invio, premere su, premere invio di nuovo senza modificare nulla, quindi ripetere la procedura per più copie. Più veloce. –

+0

molto utile grazie! – Elankeeran

11

si sa per certo, che la chiave DUPLICATO attiverà, in tal modo è possibile selezionare il MAX (ID) +1 a priori: il

INSERT INTO invoices SELECT MAX(ID)+1, ... other fields ... FROM invoices AS iv WHERE iv.ID=XXXXX 
+1

sì, ma non voglio digitare tutti gli altri campi (ce ne sono più o meno 20, e potrebbero cambiare nel tempo). Non voglio cambiare il codice ogni volta che cambia il tablestrutro. – Digits

+0

Dovrai farlo. È meglio creare uno script che generi l'istruzione SQL da un elenco di campi. È banale. – Ingo

+0

L'unica altra alternativa è usare un trigger di inserimento (se mysql lo supporta). – Ingo

1

mi serviva anche questo; la mia soluzione era usare SQLYOG (versione gratuita) per esportare il record desiderato come SQL (crea un inserto).

Ho quindi modificato manualmente questo per rimuovere l'id in quanto questo deve essere generato automaticamente e quindi copiato l'inserto in SQLYog per eseguirlo. Questo era indolore. Immagino che un sacco di altre GUI MySQL possono fare anche questo.

Questo mi fornisce un record che posso utilizzare a scopo di test su un sistema live.

Ora ho questo inserto da riutilizzare, poiché la tabella viene riscritta giornalmente.

75

La risposta di Alex richiede un po 'di attenzione (ad esempio il blocco o una transazione) in ambienti multi-cliente.

Supponendo che il campo AUTO ID sia il primo nella tabella (un caso normale), è possibile utilizzare le transazioni implicite .

 
    CREATE TEMPORARY TABLE tmp SELECT * from invoices WHERE ...; 
    ALTER TABLE tmp drop ID; # drop autoincrement field 
    # UPDATE tmp SET ...; # just needed to change other unique keys 
    INSERT INTO invoices SELECT 0,tmp.* FROM tmp; 
    DROP TABLE tmp; 

Dalla documentazione MySQL:

Utilizzando AUTO_INCREMENT: è anche possibile assegnare esplicitamente NULL o 0 alla colonna per generare numeri di sequenza.

+3

Questo è stato molto utile per me, grazie. – rotanimod

+0

Esattamente quello che volevo, grazie! – Yos

+0

Inserisce il record con un ID 0 per me, anche se ho un campo AUTO_INCREMENT.Cambiandolo su null ha funzionato, quindi ti suggerisco di cambiare il codice per usare null invece di 0. Sono su MySQL 5.5.35 (Ubuntu). –

2

Ho un problema simile, e questo è whant che sto facendo

insert into Preguntas (`EncuestaID`, `Tipo` , `Seccion` , `RespuestaID` , `Texto`) select '23', `Tipo`, `Seccion`, `RespuestaID`, `Texto` from Preguntas where `EncuestaID`= 18 

Conosci Preguntas:

CREATE TABLE IF NOT EXISTS `Preguntas` (
    `ID` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `EncuestaID` int(11) DEFAULT NULL, 
    `Tipo` char(5) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `Seccion` int(11) DEFAULT NULL, 
    `RespuestaID` bigint(11) DEFAULT NULL, 
    `Texto` text COLLATE utf8_unicode_ci , 
    PRIMARY KEY (`ID`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=522 ; 

Così, il ID viene automaticamente incrementato e anche io sto usando un valore fisso ('23') per `EncuestaID

+0

scusate, mi sono appena reso conto che non volete usare il nome della colonna, quindi questo non si applica –

10

L'approccio è buono ma il problema è che si utilizza" * "invece di elencare i campi nome S.Se si inseriscono tutti i nomi delle colonne, la chiave primaria di eccezione lo script funzionerà come incantesimo su uno o più record.

INSERT INTO invoices (iv.field_name, iv.field_name,iv.field_name ) SELECT iv.field_name, iv.field_name,iv.field_name FROM invoices AS iv WHERE iv.ID=XXXXX

0

leggera variazione, differenza principale è quello di impostare il campo chiave primaria ("variabile") null, che produce un avvertimento, ma funziona. Impostando la chiave primaria su null, l'incremento automatico funziona quando si inserisce il record nell'ultima istruzione.

Questo codice Pulisce anche i precedenti tentativi, e può essere eseguito più di una volta senza problemi:

DELETE FROM `tbl` WHERE varname="primary key value for new record"; 
DROP TABLE tmp; 
CREATE TEMPORARY TABLE tmp SELECT * FROM `tbl` WHERE varname="primary key value for old record"; 
UPDATE tmp SET varname=NULL; 
INSERT INTO `tbl` SELECT * FROM tmp; 
1

Volevo solo per estendere la grande risposta di Alex per rendere più appropriato se vi capita di voler duplicare un intero insieme di record:

SET @x=7; 
CREATE TEMPORARY TABLE tmp SELECT * FROM invoices; 
UPDATE tmp SET [email protected]; 
INSERT INTO invoices SELECT * FROM tmp; 

ho dovuto fare questo e ho trovato la risposta di Alex un perfetto punto di partenza !. Ovviamente, devi impostare @x sul numero di riga più alto nella tabella (sono sicuro che potresti afferrarlo con una query). Questo è utile solo in questa situazione molto specifica, quindi fai attenzione ad usarlo quando non desideri duplicare tutte le righe. Regola la matematica secondo necessità.

3

Una risposta tardiva lo so, ma è ancora una domanda comune, vorrei aggiungere un'altra risposta che ha funzionato per me, con solo l'utilizzo della riga singola insert into dichiarazione, e penso che sia semplice, senza creare alcun nuova tabella (dal momento che potrebbe essere un problema con i permessi CREATE TEMPORARY TABLE):

INSERT INTO invoices (col_1, col_2, col_3, ... etc) 
    SELECT 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... 
    t.updated_date, 
    FROM invoices t; 

La soluzione sta lavorando per AUTO_INCREMENT colonna id, in caso contrario, è possibile aggiungere ID colonna nonché alla dichiarazione:

INSERT INTO invoices (ID, col_1, col_2, col_3, ... etc) 
    SELECT 
    MAX(ID)+1, 
    t.col_1, 
    t.col_2, 
    t.col_3, 
    ... etc , 
    FROM invoices t; 

è davvero facile e diretto, puoi aggiornare qualsiasi altra cosa in una singola riga senza alcuna seconda istruzione di aggiornamento per dopo, (es: aggiorna una colonna del titolo con testo extra o sostituendo una stringa con un'altra), anche tu puoi essere specifico con cosa vuoi duplicare esattamente, se tutto è così, se qualcuno lo può fare.

+1

Questa è anche una buona base per modificare alcuni campi durante la copia. Ho appena usato 'INSERT in wp_options SELECT NULL, 'theme_mods_twopress', option_value, autoload FROM wp_options dove option_name = 'theme_mods_onepress';' per copiare mentre aumentava la voce ('AUTO_INCREMENT'' trucco NULL' dall'alto) e il campo 'option_name' anche. –

+0

Sì .. Buona idea per me. Grazie!! –

Problemi correlati