Gibt es eine Möglichkeit, mit ON DUPLICATE KEY alles zu aktualisieren, was ich einfügen wollte?


75

Ich weiß, dass Sie ON DUPLICATE KEY UPDATEeinen bestimmten Wert aktualisieren können, wenn für diesen Schlüssel bereits ein Datensatz vorhanden ist.

Ich kann dies tun:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1, 2, 3)
ON DUPLICATE KEY UPDATE `a`=1, `b`=2, `c`=3

Aber wie kann ich das tun, ohne die Spalten und Werte zweimal ausschreiben zu müssen?


Antworten:


103

Leider nicht.

Sie können auf halbem Weg dorthin gelangen, indem Sie den Wert nicht wiederholen müssen:

INSERT INTO `tableName` (`a`,`b`,`c`) VALUES (1,2,3)
  ON DUPLICATE KEY UPDATE `a`=VALUES(`a`), `b`=VALUES(`b`), `c`=VALUES(`c`);

Sie müssen jedoch noch die Spalten auflisten.


@Neal: Deine Werte zum Einfügen sind komplex, nehme ich an?
Leichtigkeitsrennen im Orbit

@Neal: Zieh das Semikolon aus. Es ist alles eine Frage.
Leichtigkeitsrennen im Orbit

Haha danke ^ _ ^. Ich habe nicht bemerkt, dass ich es dort gelassen hatte. Ich versuche es jetzt.
Naftali aka Neal

3
@ Sohaib : UPDATE a = VALUES(a)+a, b = VALUES(b)+b, c = VALUES(c)+c?
Leichtigkeitsrennen im Orbit

2
Die Verwendung von VALUES () zum Verweisen auf die neuen Zeilen und Spalten ist ab MySQL 8.0.20 veraltet und kann in einem zukünftigen dev.mysql.com/doc/refman/8.0/en/…
BhendiGawaar

39

verwenden REPLACE INTO

Die Bedeutung von REPLACE INTOist, dass, wenn der neue Datensatz neue Schlüsselwerte enthält, er als neuer Datensatz eingefügt wird.

Wenn der neue Datensatz Schlüsselwerte enthält, die mit einem bereits vorhandenen Datensatz übereinstimmen, wird die Schlüsselverletzung ignoriert und der neue Datensatz ersetzt den bereits vorhandenen Datensatz.


5
Ah, das könnte viel besser sein. Es ist jedoch zu beachten, dass alle Felder, die nicht explizit in der Abfrage angegeben sind, standardmäßig verwendet werden, was sich offensichtlich vom ON DUPLICATE KEY UPDATEVerhalten unterscheidet.
Leichtigkeitsrennen im Orbit

66
Hinweis: REPLACEWenn der Schlüssel des Datensatzes mit etwas übereinstimmt, das bereits vorhanden ist, werden die alten Zeilen gelöscht und die neue eingefügt . Dies kann eine große Sache sein, wenn Sie mit Triggern oder Fremdschlüsseleinschränkungen herumspielen.
CHao

3
Guter Punkt. Sie riskieren einige erhebliche Kettenreaktionen, denke ich.
Leichtigkeitsrennen im Orbit

1
Beachten Sie auch, dass mysqli_insert_id () nicht funktioniert! "Wenn die letzte Abfrage keine INSERT- oder UPDATE-Anweisung war oder wenn die geänderte Tabelle keine Spalte mit dem Attribut AUTO_INCREMENT enthält, gibt diese Funktion Null zurück."
Edward

Um auf den Kommentar von cHao einzugehen, bedeutet dies, dass Ihre neuen Einträge andere automatische Inkrementierungs-IDs haben als die alten "ersetzten" Einträge. Dies kann ziemlich schrecklich sein, wenn Sie eine Verknüpfungstabelle irgendwo verwenden, die den Ersatz nicht fängt
Abraham Brookes

15

Wenn es nützlich ist, habe ich eine Abfrage durchgeführt, um zu vermeiden, dass der letzte Teil der Abfrage "bei Duplikaten" für Versionen> = 5.0 von Hand geschrieben wird:

SELECT GROUP_CONCAT( CONCAT(COLUMN_NAME,"=values(", COLUMN_NAME,")") SEPARATOR ", ") FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'database_name' AND TABLE_NAME = 'table_name';

und seine Ausgabe ist diese:

a=values(a), b=values(b), c=values(c), d=values(d)

In einer Tabelle mit den Spalten a, b, c und d können Sie den ersten Teil der Abfrage anhängen:

INSERT INTO `tableName` (`a`,`b`,`c`, `d`) VALUES (1,2,3,4) ON DUPLICATE KEY UPDATE a=values(a), b=values(b), c=values(c), d=values(d)

UPDATE: Für eine sehr lange Liste von Spalten wird möglicherweise eine abgeschnittene Ausgabe angezeigt. Sie können diese Anweisung vor der obigen Abfrage verwenden (danke Onkel iroh ):

SET SESSION group_concat_max_len = 1000000;

2
Ich liebe das. Manchmal brauche ich das vor Ihrer sehr hilfreichen Frage. SET SESSION group_concat_max_len = 1000000;
Onkel Iroh

1
Du bist toll!
Damilola Olowookere

1

Per @ BhendiGawaars Kommentar zu @Lightness Races in Orbits Antwort, hier ist die MySQL 8.019+ Version:

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new
  ON DUPLICATE KEY UPDATE c = new.a+new.b;

ODER

INSERT INTO t1 (a,b,c) VALUES (1,2,3),(4,5,6) AS new(m,n,p)
  ON DUPLICATE KEY UPDATE c = m+n;

Funktioniert auch mit set:

INSERT INTO t1 SET a=1,b=2,c=3 AS new
  ON DUPLICATE KEY UPDATE c = new.a+new.b;

INSERT INTO t1 SET a=1,b=2,c=3 AS new(m,n,p)
  ON DUPLICATE KEY UPDATE c = m+n;

Direkt aus MySQL Docs kopiert

Die Verwerfungswarnung über die Verwendung von VALUES:

Die Verwendung von VALUES () zum Verweisen auf die neuen Zeilen und Spalten ist ab MySQL 8.0.20 veraltet und muss in einer zukünftigen Version von MySQL entfernt werden. Verwenden Sie stattdessen Zeilen- und Spaltenaliasnamen, wie in den nächsten Absätzen dieses Abschnitts beschrieben.


0

Ich weiß, dass dies eine alte Frage ist, und dies ist eine etwas unkonventionelle Antwort, aber ich bin auf dasselbe gestoßen und hatte Probleme beim Festlegen der Eigenschaft group_concat_max_len, die in einer anderen Antwort erwähnt wurde, und habe immer ein abgeschnittenes Ergebnis erhalten. Eine andere Option, die ich letztendlich beim Schreiben eines langen Skripts gewählt habe, war die Verwendung dieser Formel in Excel:

=SUBSTITUTE(TRIM(A1), ",", "") & " = VALUES(" & SUBSTITUTE(TRIM(A1), ",", "") & "),"

Dabei ist A1 die Zelle, in die Sie den Feldnamen kopieren. Um dies schnell zu erledigen, klicke ich mit der rechten Maustaste auf die Tabelle und kopiere die select-Anweisung in die Zwischenablage, in der alle Spaltennamen angegeben sind. Die Formel entfernt die Kommas.

Hoffe das hilft jemandem!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.