2013-03-06 8 views
5

Ich bin auf der Suche nach einer Standard-SQL-Anweisung "UPSERT". Ein Aufruf zum Einfügen und Aktualisieren, falls vorhanden.SQL-Standard-UPSERT Anruf

Ich bin auf der Suche nach einem funktionierenden, effizienten und plattformübergreifenden Anruf.

Ich habe gesehen MERGE, UPSERT, REPLACE, INSERT .. ON DUPLICATE UPDATE aber keine Aussage erfüllt die Bedürfnisse.

BTW Ich verwende MYSQL und HSQLDB für unitests. Ich verstehe, dass HSQLDB begrenzt ist und möglicherweise nicht deckt, was ich brauche, aber ich konnte einen Standardweg auch ohne es nicht finden. Eine Aussage, dass nur MYSQL und HSQLDB auch für jetzt genug sind.

Ich habe mich eine Weile umgeschaut und konnte keine Antwort bekommen.

Meine Tabelle:

CREATE TABLE MY_TABLE (
    MY_KEY varchar(50) NOT NULL , 
    MY_VALUE varchar(50) DEFAULT NULL, 
    TIME_STAMP bigint NOT NULL, 
    PRIMARY KEY (MY_KEY) 
); 

Jede Idee?

Thanx;)

+0

'INSERT .. ON DUPLICATE UPDATE' ist der Schlüssel in' mYSQL'. Können Sie einige Aufzeichnungen oder vielleicht die Tabellenstruktur zeigen? –

+0

Ja, aber es wird nur in MySQL unterstützt. HSQLDB und alle anderen benutzen es nicht ... – BobTheBuilder

+0

gibt es eine ANSI-Zusammenführung (http://en.wikipedia.org/wiki/Merge_%28SQL%29), aber es ist nicht in allen DBMS implementiert. Also keine Hoffnung auf ein universelles Kommando. –

Antwort

4

Die einzige Lösung, die sowohl von MySQL als auch von HSQLDB unterstützt wird, besteht darin, die zu ersetzenden Zeilen abzufragen und bedingt entweder INSERT oder UPDATE. Dies bedeutet, dass Sie mehr Anwendungscode schreiben müssen, um die Unterschiede zwischen RDBMS-Implementierungen zu kompensieren.

  1. START TRANSACTION.
  2. WÄHLEN SIE ... FÜR UPDATE.
  3. Wenn das SELECT Zeilen findet, UPDATE.
  4. Sonst, INSERT.
  5. COMMIT.

MySQL unterstützt die ANSI SQL MERGE-Anweisung nicht. Es unterstützt REPLACE und INSERT ... ON DUPLICATE KEY UPDATE. Siehe meine Antwort auf "INSERT IGNORE" vs "INSERT ... ON DUPLICATE KEY UPDATE" für mehr dazu.


Re Kommentare: Ja, ein anderer Ansatz ist es, nur die INSERT versuchen und sehen, ob es gelingt. Ansonsten führe ein UPDATE durch. Wenn Sie INSERT versuchen und es einen doppelten Schlüssel trifft, wird ein Fehler generiert, der bei einigen Client-Schnittstellen zu einer Ausnahme wird. Der Nachteil dabei ist, dass MySQL eine neue Auto-Inkrement-ID erzeugt, selbst wenn das INSERT fehlschlägt. Sie haben also Lücken. Ich weiß, dass Lücken in der Auto-Increment-Sequenz normalerweise keine Sorge sind, aber ich half einem Kunden im letzten Jahr, der aufgrund dieses Effekts Lücken zwischen 1000-1500 zwischen erfolgreichen Inserts hatte, und das Ergebnis war, dass sie die Reichweite eines INT in ihrem Primärschlüssel.

Wie @baraky sagt, könnte man stattdessen zuerst das UPDATE versuchen, und wenn das null Zeilen betrifft, dann führe das INSERT aus. Mein Kommentar zu dieser Strategie ist, dass UPDATE Null Zeilen keine Ausnahme ist - Sie müssen nach "UPDATE" nach "Anzahl der betroffenen Zeilen" suchen, um zu wissen, ob es erfolgreich war oder nicht.

Wenn Sie jedoch die Anzahl der betroffenen Zeilen abfragen, kehren Sie zum ursprünglichen Problem zurück: Sie müssen verschiedene Abfragen in MySQL und HSQLDB verwenden.

HSQLDB:

CALL DIAGNOSTICS(ROW_COUNT); 

MySQL:

SELECT ROW_COUNT(); 
+0

Oder führen Sie INSERT, fangen SQLException und wenn es eine Integritätsbedingung Verletzung ist, führen Sie eine UPDATE – fredt

+0

Eigentlich ist das (fast), was ich tun werde - ich werde update, fangen die Ausnahme (wie Updates sind der übliche Fall für ich) und einfügen, wenn fehlschlägt. Danke! – BobTheBuilder

3

Die Syntax eine Upsert in einem einzigen Befehl dafür variiert je nach RDBMS.

In MySQL ist es INSERT...ON DUPLICATE KEY UPDATE

In HSQLDB es ist MERGE

Wenn Sie eine Cross-Plattform-Lösung wollen, dann werden Sie mehrere Befehle verwenden müssen. Überprüfen Sie zuerst die vorhandene Zeile, und fügen Sie sie dann entsprechend ein oder aktualisieren Sie sie.

+0

Ich möchte nicht mehrere Befehle verwenden. Irgendwelche anderen Ideen, wie Test und Entwickler den gleichen Code laufen lassen? – BobTheBuilder

+0

Ich empfehle immer noch, es mit bedingten Code zu tun.Wenn Sie das nicht tun, dann erwägen Sie, Ihren Test zu standardisieren Entwicklungsumgebungen, um dasselbe RD zu verwenden BMS. –

+0

@baraky: Wenn Sie mehrere DBMS unterstützen möchten, werden Sie nie in der Lage sein, jedes Problem mit einer Anweisung zu lösen, die auf allen DBMS ausgeführt wird. Bereiten Sie sich darauf vor, DBMS-spezifische Anweisungen zu haben. Alles andere wird scheitern. –