Come copiare una riga e inserirla nella stessa tabella con un campo di incremento automatico in MySQL?


233

In MySQL sto cercando di copiare una riga con un incremento automatico column ID=1 e inserire i dati nella stessa tabella di una nuova riga con column ID=2.

Come posso farlo in una singola query?

Risposte:


351

Utilizzare INSERT ... SELECT:

insert into your_table (c1, c2, ...)
select c1, c2, ...
from your_table
where id = 1

dove c1, c2, ...sono tutte le colonne tranne id. Se si desidera inserire esplicitamente idtra 2, includerlo nell'elenco INSERT delle colonne e in SELECT:

insert into your_table (id, c1, c2, ...)
select 2, c1, c2, ...
from your_table
where id = 1

idOvviamente dovrai occuparti di un possibile duplicato di 2 nel secondo caso.


1
Potresti ottenere a livello di codice quindi i nomi delle colonne usando INFORMATION_SCHEMA ... Mi chiedo se potresti farlo come una sottoquery e alcune funzioni di stringa? Hmmm ...
Yzmir Ramirez,

1
@Yzmir: finiresti per usare l'SQL dinamico e questo di solito richiederebbe la creazione di una procedura memorizzata. Sembra più problemi di quanti ne valga la pena quando dovresti comunque avere un elenco di nomi di colonne a portata di mano.
mu è troppo corto il

6
D'accordo ... dalla mia esperienza una volta avviata la Stored Procedure non torni indietro - sei sposato con quel database ora e ti faccio solo aumentare i costi ogni volta che vuoi cambiare.
Yzmir Ramirez,

11
@YzmirRamirez, sembra che il matrimonio sia intrinsecamente negativo. :)
Prof. Falken,

1
Come aggiungere un valore personalizzato nella colonna con tutti gli altri campi copiati?
Manish Kumar

49

IMO, il migliore sembra usare le istruzioni sql solo per copiare quella riga, mentre allo stesso tempo fa riferimento solo alle colonne che devi e vuoi cambiare.

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY

SELECT * FROM your_table WHERE id=1;
UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;

Vedi anche av8n.com - Come clonare un record SQL

Benefici:

  • Le istruzioni SQL 2 menzionano solo i campi che devono essere modificati durante il processo di clonazione. Non conoscono o si preoccupano di altri campi. Gli altri campi vanno avanti per la corsa, invariati. Questo rende le istruzioni SQL più facili da scrivere, più facili da leggere, più facili da mantenere e più estensibili.
  • Vengono utilizzate solo le normali istruzioni MySQL. Non sono richiesti altri strumenti o linguaggi di programmazione.
  • Un record completamente corretto viene inserito in your_tableun'operazione atomica.

3
Sembra che questo bel trucco (mi è piaciuto, ma non ha funzionato per me) non funziona su tabelle che contengono colonne TEXT / VARCHAR. L'ho provato e ho ottenuto: (1163): il tipo di tabella utilizzata non supporta le colonne BLOB / TEXT. Ciò ovviamente limita molto l'utilizzo su MySQL! Potrebbe essere che in futuro questi limiti vengano aumentati o su altri sistemi db funzionerà, ma per ora è davvero limitato.
Juergen,

Mi piace molto l'uso intelligente della tabella temporanea. Molto utile per le tabelle con tonnellate di colonne!
Lasma,

1
Sembra carino, ma quando eseguo la prima query in MySQL, ottengo Error Code: 1113. A table must have at least 1 column.
fisica il

3
La migliore risposta per molte colonne. Ma SET id=NULLpuò causare un errore Column 'id' cannot be null. Dovrebbe essere sostituito daUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder

1
@spedizione fisica devi assicurarti che le prime due righe siano una frase.
Samuurai,

16

Di 'che il tavolo è user(id, user_name, user_email).

È possibile utilizzare questa query:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)

29
Dovresti sempre specificare i nomi delle colonne quando usi INSERT, altrimenti otterrai strani e interessanti bug quando cambi lo schema.
mu è troppo corto il

2
Strano e interessante, anzi. : D
sparkyShorts

Non funziona con sqlite. Result: near "SELECT": syntax error
Kyb,

10

Questo ha aiutato e supporta colonne BLOB / TEXT.

CREATE TEMPORARY TABLE temp_table
AS
SELECT * FROM source_table WHERE id=2;
UPDATE temp_table SET id=NULL WHERE id=2;
INSERT INTO source_table SELECT * FROM temp_table;
DROP TEMPORARY TABLE temp_table;
USE source_table;

In che modo è meglio di altre risposte qui?
Smar,

3
Penso che sia abbastanza buono se hai un tavolo con 100 di campi. Tranne che potrebbe esserci un vincolo non nullo sull'id che lo fa fallire
Loïc Faure-Lacroix

Codice errore: 1136. Il conteggio delle colonne non corrisponde al conteggio dei valori nella riga 1
Oleksii Kyslytsyn

Questo è molto meglio se hai una tabella con centinaia di colonne.
Tyler S. Loeper,

Non è quello che diceva parvus, anni prima?
ToolmakerSteve

7

Per una soluzione rapida e pulita che non richiede di nominare le colonne, è possibile utilizzare un'istruzione preparata come descritto qui: https://stackoverflow.com/a/23964285/292677

Se hai bisogno di una soluzione complessa in modo da poterlo fare spesso, puoi usare questa procedura:

DELIMITER $$

CREATE PROCEDURE `duplicateRows`(_schemaName text, _tableName text, _whereClause text, _omitColumns text)
SQL SECURITY INVOKER
BEGIN
  SELECT IF(TRIM(_omitColumns) <> '', CONCAT('id', ',', TRIM(_omitColumns)), 'id') INTO @omitColumns;

  SELECT GROUP_CONCAT(COLUMN_NAME) FROM information_schema.columns 
  WHERE table_schema = _schemaName AND table_name = _tableName AND FIND_IN_SET(COLUMN_NAME,@omitColumns) = 0 ORDER BY ORDINAL_POSITION INTO @columns;

  SET @sql = CONCAT('INSERT INTO ', _tableName, '(', @columns, ')',
  'SELECT ', @columns, 
  ' FROM ', _schemaName, '.', _tableName, ' ',  _whereClause);

  PREPARE stmt1 FROM @sql;
  EXECUTE stmt1;
END

Puoi eseguirlo con:

CALL duplicateRows('database', 'table', 'WHERE condition = optional', 'omit_columns_optional');

Esempi

duplicateRows('acl', 'users', 'WHERE id = 200'); -- will duplicate the row for the user with id 200
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts'); -- same as above but will not copy the created_ts column value    
duplicateRows('acl', 'users', 'WHERE id = 200', 'created_ts,updated_ts'); -- same as above but also omits the updated_ts column
duplicateRows('acl', 'users'); -- will duplicate all records in the table

NOTA BENE: Questa soluzione è solo per qualcuno che ripeterà ripetutamente le righe in molte tabelle, spesso. Potrebbe essere pericoloso nelle mani di un utente canaglia.


3

Puoi anche passare '0' come valore della colonna all'incremento automatico, al momento della creazione del record verrà utilizzato il valore corretto. Questo è molto più semplice delle tabelle temporanee.

Fonte: copia di righe in MySQL (vedi il secondo commento, di TRiG, ​​alla prima soluzione, di Lore)


1
Questo metodo funziona con le versioni più recenti di MySQL quando NULL non è accettabile.
err

3

Molte grandi risposte qui. Di seguito è riportato un esempio della procedura memorizzata che ho scritto per eseguire questa attività per un'app Web che sto sviluppando:

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON

-- Create Temporary Table
SELECT * INTO #tempTable FROM <YourTable> WHERE Id = Id

--To trigger the auto increment
UPDATE #tempTable SET Id = NULL 

--Update new data row in #tempTable here!

--Insert duplicate row with modified data back into your table
INSERT INTO <YourTable> SELECT * FROM #tempTable

-- Drop Temporary Table
DROP TABLE #tempTable

nella versione corrente di MariaDB / MySQL l'impostazione id = null dà # 1048 - La colonna 'id' non può essere nulla, l'impostazione id = 0 funziona;
shelbypereira,

2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

3
In che modo è meglio di altre risposte qui?
Smar,

1
@smar imo è più pulito da capire
Satbir Kira,

2

Se sei in grado di utilizzare MySQL Workbench, puoi farlo facendo clic con il pulsante destro del mouse sulla riga e selezionando "Copia riga", quindi facendo clic con il pulsante destro del mouse sulla riga vuota e selezionando "Incolla riga", quindi modificando l'ID e quindi facendo clic su "Applica".

Copia la riga:

inserisci qui la descrizione dell'immagine

Incolla la riga copiata nella riga vuota:

inserisci qui la descrizione dell'immagine

Cambia l'ID:

inserisci qui la descrizione dell'immagine

Applicare:

inserisci qui la descrizione dell'immagine


0

Stavo cercando la stessa funzione ma non uso MySQL. Volevo copiare TUTTI i campi tranne ovviamente la chiave primaria (id). Questa era una query one-shot, da non usare in nessuno script o codice.

Mi sono orientato con PL / SQL ma sono sicuro che qualsiasi altro IDE SQL lo farebbe. Ho fatto una base

SELECT * 
FROM mytable 
WHERE id=42;

Quindi esportarlo in un file SQL dove ho potuto trovare

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (1, 2, 3, ..., 42);

L'ho appena modificato e utilizzato:

INSERT INTO table (col1, col2, col3, ... , col42) 
VALUES (mysequence.nextval, 2, 3, ..., 42);

0

Tendo a usare una variazione di ciò che mu è pubblicato troppo breve:

INSERT INTO something_log
SELECT NULL, s.*
FROM something AS s
WHERE s.id = 1;

Fintanto che le tabelle hanno campi identici (tranne l'incremento automatico sulla tabella di registro), allora funziona bene.

Poiché utilizzo le procedure memorizzate quando possibile (per semplificare la vita di altri programmatori che non hanno familiarità con i database), questo risolve il problema di dover tornare indietro e aggiornare le procedure ogni volta che aggiungi un nuovo campo a una tabella.

Assicura inoltre che se aggiungi nuovi campi a una tabella, questi inizieranno a comparire immediatamente nella tabella di registro senza dover aggiornare le query del database (a meno che ovviamente non ne abbia alcuni che impostano esplicitamente un campo)

Avvertimento: dovrai assicurarti di aggiungere tutti i nuovi campi a entrambe le tabelle contemporaneamente in modo che l'ordine dei campi rimanga lo stesso ... altrimenti inizierai a ricevere bug strani. Se sei l'unico che scrive interfacce di database E stai molto attento, allora funziona bene. Altrimenti, attenersi alla denominazione di tutti i campi.

Nota: Ripensandoci, a meno che tu non stia lavorando a un progetto solista che sei sicuro che non ci saranno altri che lavorano su di esso, cerca di elencare tutti i nomi dei campi in modo esplicito e aggiorna le tue dichiarazioni di registro quando lo schema cambia. Questa scorciatoia probabilmente non vale il mal di testa a lungo termine che può causare ... specialmente su un sistema di produzione.


0
INSERIRE IN `dbMyDataBase``tblMyTable` 
(
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

SELEZIONARE 
    NULLO,  
    `Column2`, 
    `Column3`, 
    Colonna AS "CustomValue" 4 
DA `dbMyDataBase``tblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
; 
/ * mySQL 5.6 * /

3
Prova ad aggiungere qualche spiegazione più dettagliata o come si espande sulle altre risposte
Azsgy,

-1

Dump della riga che si desidera sql e quindi utilizzare l'SQL generato, meno la colonna ID per reimportarla.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.