Wie kopiere ich eine Zeile und füge sie mit einem Autoincrement-Feld in MySQL in dieselbe Tabelle ein?

231

In MySQL versuche ich, eine Zeile mit einer automatischen Inkrementierung zu kopieren column ID=1und die Daten in dieselbe Tabelle einzufügen wie eine neue Zeile mit column ID=2.

Wie kann ich das in einer einzigen Abfrage tun?

Navdroid
quelle

Antworten:

349

Verwendung INSERT ... SELECT:

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

Wo c1, c2, ...sind alle Spalten außer id. Wenn Sie explizit mit einer idvon 2 einfügen möchten, fügen Sie diese in Ihre INSERT-Spaltenliste und Ihre SELECT:

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

idIm zweiten Fall müssen Sie sich natürlich um ein mögliches Duplikat von 2 kümmern .

mu ist zu kurz
quelle
1
Sie könnten dann programmatisch die Namen der Spalten mit INFORMATION_SCHEMA abrufen ... Ich frage mich, ob Sie dies als Unterabfrage und einige Zeichenfolgenfunktionen tun könnten. Hmmm ...
Yzmir Ramirez
1
@Yzmir: Am Ende müssten Sie dynamisches SQL verwenden, und dafür müsste normalerweise eine gespeicherte Prozedur erstellt werden. Es scheint mehr Mühe zu geben, als es wert ist, wenn Sie trotzdem eine Liste mit Spaltennamen zur Hand haben sollten.
Mu ist zu kurz
6
Einverstanden ... aus meiner Erfahrung, wenn Sie einmal gespeichert sind, gehen Sie nicht zurück - Sie sind jetzt mit dieser Datenbank verheiratet und erhöhen nur die Kosten, wann immer Sie Änderungen vornehmen möchten.
Yzmir Ramirez
11
@YzmirRamirez, du machst es so, als wäre die Ehe von Natur aus eine schlechte Sache. :)
Prof. Falken Vertrag verletzt
1
Wie füge ich einen benutzerdefinierten Wert in der Spalte mit allen anderen kopierten Feldern hinzu?
Manish Kumar
48

IMO, das Beste scheint SQL-Anweisungen nur zum Kopieren dieser Zeile zu verwenden, während gleichzeitig nur auf die Spalten verwiesen wird, die Sie ändern müssen und möchten.

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;

Siehe auch av8n.com - So klonen Sie einen SQL-Datensatz

Leistungen:

  • Die SQL-Anweisungen 2 erwähnen nur die Felder, die während des Klonvorgangs geändert werden müssen. Sie kennen andere Bereiche nicht oder kümmern sich nicht darum. Die anderen Felder machen sich unverändert auf den Weg. Dadurch sind die SQL-Anweisungen einfacher zu schreiben, leichter zu lesen, leichter zu warten und erweiterbarer.
  • Es werden nur normale MySQL-Anweisungen verwendet. Es sind keine weiteren Tools oder Programmiersprachen erforderlich.
  • Ein vollständig korrekter Datensatz wird your_tablein eine atomare Operation eingefügt .
Parvus
quelle
3
Es scheint, dass dieser nette Trick (ich mochte ihn, aber er hat bei mir nicht funktioniert) nicht für Tabellen funktioniert, die TEXT / VARCHAR-Spalten enthalten. Ich habe es versucht und bekam: (1163): Der verwendete Tabellentyp unterstützt keine BLOB / TEXT-Spalten. Das schränkt natürlich die Nutzung unter MySQL sehr ein! Könnte sein, dass in Zukunft diese Grenzen aufgehoben werden oder auf anderen DB-Systemen funktioniert es, aber im Moment ist es wirklich zu begrenzt.
Jürgen
Ich mag die clevere Verwendung von temporären Tischen sehr. So nützlich für Tabellen mit einer Menge Spalten!
Lasma
1
Sieht gut aus, aber wenn ich die erste Abfrage in MySQL ausführe, bekomme ich Error Code: 1113. A table must have at least 1 column.
körperliche
3
Beste Antwort für viele Spalten. Aber SET id=NULLkann einen Fehler verursachen Column 'id' cannot be null. Sollte ersetzt werden durchUPDATE temp_table SET id = (SELECT MAX(id) + 1 as id FROM your_table);
Modder
1
@physicalattraction Sie müssen sicherstellen, dass die ersten beiden Zeilen eine Aussage sind.
Samuurai
16

Angenommen, der Tisch ist user(id, user_name, user_email).

Sie können diese Abfrage verwenden:

INSERT INTO user (SELECT NULL,user_name, user_email FROM user WHERE id = 1)
Vijay
quelle
29
Sie sollten bei der Verwendung von INSERT immer die Spaltennamen angeben, da sonst seltsame und interessante Fehler auftreten, wenn sich Ihr Schema ändert.
Mu ist zu kurz
2
Seltsam und interessant. : D
sparkyShorts
Funktioniert nicht mit SQLite. Result: near "SELECT": syntax error
Kyb
10

Dies hat geholfen und unterstützt BLOB / TEXT-Spalten.

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;
Petr Hladík
quelle
Inwiefern ist dies besser als andere Antworten hier?
Smar
3
Ich finde es ziemlich gut, wenn Sie eine Tabelle mit 100 Feldern haben. Außer es gibt möglicherweise eine Nicht-Null-Einschränkung für die ID, die zum
Loïc Faure-Lacroix,
Fehlercode: 1136. Die Spaltenanzahl stimmt nicht mit der
Wertanzahl
Dies ist viel besser, wenn Sie eine Tabelle mit Hunderten von Spalten haben.
Tyler S. Loeper
Ist es nicht das, was Parvus Jahre zuvor gesagt hat?
ToolmakerSteve
7

Für eine schnelle und saubere Lösung, bei der Sie keine Spalten benennen müssen, können Sie eine vorbereitete Anweisung verwenden, wie hier beschrieben: https://stackoverflow.com/a/23964285/292677

Wenn Sie eine komplexe Lösung benötigen, damit Sie dies häufig tun können, können Sie dieses Verfahren anwenden:

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

Sie können es ausführen mit:

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

Beispiele

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

HAFTUNGSAUSSCHLUSS: Diese Lösung ist nur für Personen gedacht, die häufig wiederholt Zeilen in vielen Tabellen duplizieren. Es könnte in den Händen eines betrügerischen Benutzers gefährlich sein.

curmil
quelle
3

Sie können auch '0' als Wert für die automatisch zu erhöhende Spalte übergeben. Der richtige Wert wird beim Erstellen des Datensatzes verwendet. Dies ist so viel einfacher als temporäre Tabellen.

Quelle: Kopieren von Zeilen in MySQL (siehe den zweiten Kommentar von TRiG zur ersten Lösung von Lore)

Mark Pruce
quelle
1
Diese Methode funktioniert mit neueren MySQL-Versionen, wenn NULL nicht akzeptabel ist.
Err
3

Viele tolle Antworten hier. Unten finden Sie ein Beispiel für die gespeicherte Prozedur, die ich geschrieben habe, um diese Aufgabe für eine von mir entwickelte Web-App auszuführen:

-- 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
RBILLC
quelle
In der aktuellen Version von MariaDB / MySQL ergibt die Einstellung id = null # 1048 - Die Spalte 'id' kann nicht null sein, die Einstellung id = 0 funktioniert.
Shelbypereira
2
insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;
IR.Programmer
quelle
3
Wie ist das besser als andere Antworten hier?
Smar
1
@smar imo es ist sauberer zu verstehen
Satbir Kira
2

Wenn Sie MySQL Workbench verwenden können, können Sie dies tun, indem Sie mit der rechten Maustaste auf die Zeile klicken und "Zeile kopieren" auswählen, dann mit der rechten Maustaste auf die leere Zeile klicken und "Zeile einfügen" auswählen und dann die ID ändern Klicken Sie auf "Übernehmen".

Kopieren Sie die Zeile:

Geben Sie hier die Bildbeschreibung ein

Fügen Sie die kopierte Zeile in die leere Zeile ein:

Geben Sie hier die Bildbeschreibung ein

Ändern Sie die ID:

Geben Sie hier die Bildbeschreibung ein

Anwenden:

Geben Sie hier die Bildbeschreibung ein

Nathan Wailes
quelle
0

Ich habe nach der gleichen Funktion gesucht, aber ich benutze MySQL nicht. Ich wollte ALLE Felder kopieren, außer natürlich den Primärschlüssel (ID). Dies war eine One-Shot-Abfrage, die in keinem Skript oder Code verwendet werden sollte.

Ich habe mich mit PL / SQL zurechtgefunden, bin mir aber sicher, dass jede andere SQL-IDE dies tun würde. Ich habe ein Basic gemacht

SELECT * 
FROM mytable 
WHERE id=42;

Exportieren Sie es dann in eine SQL-Datei, in der ich die finden konnte

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

Ich habe es gerade bearbeitet und verwendet:

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

Ich neige dazu, eine Variation dessen zu verwenden, was mu zu kurz gepostet hat:

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

Solange die Tabellen identische Felder haben (mit Ausnahme des automatischen Inkrements in der Protokolltabelle), funktioniert dies einwandfrei.

Da ich nach Möglichkeit gespeicherte Prozeduren verwende (um anderen Programmierern, die mit Datenbanken nicht allzu vertraut sind, das Leben zu erleichtern), wird das Problem gelöst, dass Prozeduren jedes Mal aktualisiert werden müssen, wenn Sie einer Tabelle ein neues Feld hinzufügen.

Außerdem wird sichergestellt, dass beim Hinzufügen neuer Felder zu einer Tabelle diese sofort in der Protokolltabelle angezeigt werden, ohne dass Ihre Datenbankabfragen aktualisiert werden müssen (es sei denn, Sie haben natürlich Felder, die ein Feld explizit festlegen).

Warnung: Sie sollten sicherstellen, dass Sie beiden Tabellen gleichzeitig neue Felder hinzufügen, damit die Feldreihenfolge gleich bleibt. Andernfalls treten merkwürdige Fehler auf. Wenn Sie der einzige sind, der Datenbankschnittstellen schreibt UND Sie sehr vorsichtig sind, funktioniert dies gut. Andernfalls bleiben Sie bei der Benennung aller Ihrer Felder.

Hinweis: Wenn Sie nicht an einem Solo-Projekt arbeiten, werden Sie sicher nicht andere daran arbeiten, alle Feldnamen explizit aufzulisten und Ihre Protokollanweisungen zu aktualisieren, wenn sich Ihr Schema ändert. Diese Verknüpfung ist wahrscheinlich nicht die langfristigen Kopfschmerzen wert, die sie verursachen kann ... insbesondere auf einem Produktionssystem.

Freibeuter
quelle
0
INSERT IN `dbMyDataBase`.`tblMyTable` 
((
    `IdAutoincrement`, 
    `Column2`, 
    `Column3`, 
    `Column4` 
) 

WÄHLEN 
    NULL,  
    `Column2`, 
    `Column3`, 
    'CustomValue' AS Column4 
FROM `dbMyDataBase`.`tblMyTable` 
WHERE `tblMyTable`.`Column2` = 'UniqueValueOfTheKey' 
;; 
/ * mySQL 5.6 * /
Wojciech Skibiński
quelle
3
Versuchen Sie, eine detailliertere Erklärung hinzuzufügen, oder wie dies die anderen Antworten erweitert
Azsgy
-1

Speichern Sie die Zeile, die Sie in SQL speichern möchten, und verwenden Sie dann das generierte SQL abzüglich der ID-Spalte, um es wieder zu importieren.

Claire
quelle