Wie werden Auto_Increment-Schlüssel in INSERT behandelt (SELECT * FROM…)

12

Ich habe table1und table2in MySQL. Beide haben einen auto_incrementPrimärschlüssel id.

Wenn die Tabellenschemata übereinstimmen und ich tue, INSERT INTO table1 (SELECT * FROM table2)was passiert mit den neuen Zeilen, in die eingefügt wird table1? Behalten sie ihre alten idWerte bei und erzeugen Konflikte, wenn eine Zeile von table1dieselbe hat id? Werden neue Werte von auto_increment generiert? Kommt es auf die Speichermaschine oder die Verriegelung an?

Thomas Johnson
quelle

Antworten:

13

Sie können in eine Spalte für die automatische Inkrementierung einfügen und einen Wert angeben. Das ist okay; Es überschreibt einfach den Auto-Inkrement-Generator.

Wenn Sie versuchen, einen Wert von NULL oder 0 einzufügen DEFAULT, oder wenn Sie die Auto-Inkrement-Spalte in den Spalten Ihrer INSERT-Anweisung weglassen, wird der Auto-Inkrement-Generator aktiviert.

Es ist also in Ordnung INSERT INTO table1 SELECT * FROM table2(Sie brauchen übrigens keine Klammern). Dies bedeutet , dass die ID in Werte table2wörtlich kopiert werden, und table1wird nicht neue Werte generieren.

Wenn Sie neue Werte generieren möchten table1 , können Sie dies nicht tun SELECT *. Entweder verwenden Sie null oder 0 für die ID-Spalte:

INSERT INTO table1 SELECT 0, col1, col2, col3, ... FROM table2;

Oder Sie lassen die Spalte sowohl in der Spaltenliste der INSERT-Anweisung als auch in der Auswahlliste der SELECT-Anweisung weg:

-- No id in either case:
INSERT INTO table1 (col1, col2, col3) SELECT col1, col2, col3, ... FROM table2;

Bevor Sie fragen, gibt es in SQL keine Syntax für "select * außer einer Spalte". Sie müssen die vollständige Liste der Spaltennamen buchstabieren, die Sie einfügen möchten.

Bill Karwin
quelle
Gibt es nicht eine Option, die das Einfügen von 0 als Wert zulässt / verbietet? (In Bezug auf Ihren 2. Absatz)
Sascha Rambeaud
1
Ja, SQL_MODE = NO_AUTO_VALUE_ON_ZERO , andernfalls könnten wir niemals einen Literalwert Null in eine AI-Spalte einfügen. Wenn Sie diesen SQL-Modus verwenden, funktioniert NULL weiterhin, um den AI-Generator zu aktivieren, oder das Weglassen der Spalte funktioniert auch.
Bill Karwin
@ BillKarwin, Gibt es in Bezug auf Ihren letzten Absatz nach Erhalt des Unterergebnisses select * from tablekeine Möglichkeit, dieses Unterergebnis zu bearbeiten, um seine erste Spalte zu entfernen?
Pacerier
@ Pacerier, wenn ich richtig verstehe, fragst du, ob select *das bedeuten kann select * except for the first column. Die Antwort ist nein. select *fordert immer alle Spalten aus dieser Tabelle an. Wenn Sie eine Teilmenge möchten, müssen Sie die gewünschten Spalten buchstabieren.
Bill Karwin
@ BillKarwin, Hmm, ich habe darüber nachgedacht, die Tabelle zu vertikalen Where- Klauseln zu schwenken und sie dann zurückzuschwenken, z. B. select*from transpose(select*from(transpose(select*from table where Id=1))where col_name<>Id)oder vielleicht prägnanter als select*from table where Id=1 and $col<>Id, was denkst du?
Pacerier
3

Die ID aus der Auswahl entspricht dem Wert, der in die Tabelle eingefügt wurde. Dies führt zu einem Fehler, wenn Sie versuchen, vorhandene Zeilen zu duplizieren.

Bill Karwin: Bevor Sie fragen, gibt es in SQL keine Syntax für "select * außer einer Spalte".

Dies kann mit etwas Kreativität erreicht werden:

SET @sql = CONCAT('INSERT INTO <table> SELECT null, 
    ', (SELECT GROUP_CONCAT(COLUMN_NAME) 
    FROM information_schema.columns 
    WHERE table_schema = '<database>' 
    AND table_name = '<table>' 
    AND column_name NOT IN ('id')), ' 
from <table> WHERE id = <id>');  

PREPARE stmt1 FROM @sql;
EXECUTE stmt1;

Dies führt dazu, dass die neue Zeile anstelle der ID aus der ausgewählten Zeile eine automatisch inkrementierte ID erhält.

curmil
quelle
2
Clever, aber für mich zählt das als Rechtschreibung der vollständigen Liste der Spaltennamen, die Sie einfügen möchten.
Bill Karwin
1
Nun, es ist MySQL, das es automatisch buchstabiert und nicht manuell. Wenn Sie Tabellen mit vielen Spalten haben, wird verhindert, dass Sie eine verpassen oder einige falsch schreiben.
Curmil