2009-04-22 10 views
104

Ich habe die folgende Abfrage:MySQL ON DUPLICATE KEY - letzte Einfüge-ID?

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE a=1 

Ich möchte die ID entweder der Einsatz oder das Update. Normalerweise führe ich eine zweite Abfrage aus, um dies zu erhalten, da insert_id() nur die 'eingefügte' ID und nicht die aktualisierte ID zurückgibt.

Gibt es eine Möglichkeit INSERT/UPDATE und abrufen Sie die ID der Zeile, ohne zwei Abfragen auszuführen?

+3

Statt anzunehmen, warum testen Sie es nicht selbst? Das SQL in der obigen Bearbeitung funktioniert, und durch meine Tests ist schneller als das Abfangen eines Einfügungsfehlers, mithilfe von INSERT IGNORE, oder Auswählen, um zu sehen, ob es zuerst ein Duplikat gibt. –

+1

WARNUNG: Die vorgeschlagene Lösung funktioniert, aber der auto_increment-Wert wird weiter erhöht, auch wenn keine Einfügung erfolgt. Wenn der Duplikatschlüssel häufig vorkommt, sollten Sie nach der obigen Abfrage "alter table tabellenname AUTO_INCREMENT = 0;" ausführen, um große Lücken in Ihren ID-Werten zu vermeiden. –

Antwort

125

prüfen auf dieser Seite: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Am unteren Rand der Seite, die sie erklären, wie Sie können für Updates LAST_INSERT_ID sinnvoll machen, indem Sie einen Ausdruck vorbei th bei MySQL-Funktion.

Aus der MySQL-Dokumentation Beispiel:

Wenn eine Tabelle eine Zeile eine AUTO_INCREMENT -Spalte und INSERT ... UPDATE fügt enthält, gibt die Funktion LAST_INSERT_ID() den AUTO_INCREMENT Wert. Wenn die Anweisung stattdessen eine Zeile aktualisiert, ist LAST_INSERT_ID() nicht sinnvoll. Sie können das jedoch umgehen, indem Sie LAST_INSERT_ID (expr) verwenden. Angenommen, die ID ist die AUTO_INCREMENT-Spalte. Um LAST_INSERT_ID() sinnvoll für Updates, Einfügungen, wie folgt:

INSERT INTO table (a,b,c) VALUES (1,2,3) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3; 
+2

Irgendwie habe ich das übersehen, als ich auf diese Seite schaute. So der Update-Teil erscheint als: UPDATE ID = LAST_INSERT_ID (ID) Und das funktioniert gut. Vielen Dank! – thekevinscott

+1

Ich bin froh, dass ich helfen konnte! – fredrik

+6

Es wird gesagt, dass die PHP-Funktion mysql_insert_id() in beiden Fällen den richtigen Wert liefert: http://www.php.net/manual/en/function.mysql-insert-id.php#59718. – jayarjo

2

Sie könnten sich REPLACE ansehen, was im Wesentlichen ein Löschen/Einfügen ist, wenn der Datensatz existiert. Dies würde jedoch das Autoinkrementierungsfeld ändern, falls vorhanden, wodurch Beziehungen mit anderen Daten unterbrochen werden könnten.

+1

Ah yeah - Ich suche nach etwas, das vorherige IDs nicht loswerden wird – thekevinscott

+0

Dies kann gefährlich sein, auch weil dies auch das Löschen anderer verwandter Daten (durch Einschränkungen) verursachen kann. – Serge

0

Es ist erwähnenswert, und dies mag offensichtlich sein (aber ich sage es trotzdem für Klarheit hier), das wird blasen REPLACE weg die vorhandene übereinstimmende Zeile vor dem Einfügen Ihrer neuen Daten. ON DUPLICATE KEY UPDATE aktualisiert nur die von Ihnen angegebenen Spalten und behält die Zeile bei.

Vom manual:

Werken REPLACE genau wie INSERT, außer, dass, wenn eine alte Zeile in der Tabelle hat den gleichen Wert wie eine neue Zeile für einen Primärschlüssel oder einen eindeutigen Index, der alt Zeile wird gelöscht, bevor die neue Zeile eingefügt wird.

25

Um genau zu sein, wenn dies den die ursprüngliche Abfrage ist:

INSERT INTO table (a) VALUES (0) 
ON DUPLICATE KEY UPDATE a=1 

und ‚id‘ ist der Autoinkrement-Primärschlüssel als dies die Arbeitslösung sein würde:

INSERT INTO table (a) VALUES (0) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), a=1 

Ist alles hier: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Wenn eine Tabelle eine AUTO_INCREMENT enthält Spalte und INSERT ... UPDATE fügt eine Zeile ein, die Funktion LAST_INSERT_ID() gibt den Wert AUTO_INCREMENT zurück. Wenn die Anweisung stattdessen eine Zeile aktualisiert, ist LAST_INSERT_ID() nicht sinnvoll. Sie können dieses jedoch umgehen, indem Sie LAST_INSERT_ID (expr) verwenden. Angenommen, id ist die AUTO_INCREMENT Spalte.

+3

Ja, sehen Sie die akzeptierte Antwort für das gleiche, was Sie gesagt haben. Keine Notwendigkeit, 3 Jahre alte Beiträge wiederzubeleben. Danke für deine Mühe. – fancyPants

+1

@tombom der einzige Grund, warum ich diese Antwort geschrieben habe, ist, weil die angenommene Antwort nicht korrekt ist - es wird nicht funktionieren, wenn es nichts zu aktualisieren gibt. –

+0

+1 obwohl ich denke, die akzeptierte Antwort erwähnt, dass :) – fancyPants

0

Die vorhandenen Lösungen funktionieren, wenn Sie autoincrement verwenden. Ich habe eine Situation, wo der Benutzer ein Präfix definieren kann und es sollte die Sequenz bei 3000 neu starten. Wegen dieses unterschiedlichen Präfixes kann ich autoincrement nicht verwenden, das last_insert_id für Einfügungen leer macht. Ich löste es mit den folgenden:

INSERT INTO seq_table (prefix, id) VALUES ('$user_prefix', LAST_INSERT_ID(3000)) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id + 1); 
SELECT LAST_INSERT_ID(); 

Wenn das Präfix existiert, es erhöht wird, und füllen LAST_INSERT_ID. Wenn das Präfix nicht existiert, fügt es das Präfix mit dem Wert 3000 ein und füllt last_insert_id mit 3000.

Verwandte Themen