SQLite INSERT - ON DUPLICATE KEY UPDATE (UPSERT)

98

MySQL hat ungefähr so ​​etwas:

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON DUPLICATE KEY UPDATE hits = hits + 1;

Soweit ich weiß, ist diese Funktion in SQLite nicht vorhanden. Ich möchte wissen, ob es eine Möglichkeit gibt, denselben Effekt zu erzielen, ohne zwei Abfragen ausführen zu müssen. Wenn dies nicht möglich ist, was bevorzugen Sie:

  1. SELECT + (INSERT oder UPDATE) oder
  2. UPDATE (+ INSERT, wenn UPDATE fehlschlägt )
Alix Axel
quelle

Antworten:

31

Seit 3.24.0 unterstützt SQLite auch Upsert , sodass Sie jetzt einfach Folgendes schreiben können

INSERT INTO visits (ip, hits)
VALUES ('127.0.0.1', 1)
ON CONFLICT(ip) DO UPDATE SET hits = hits + 1;
szmate1618
quelle
3
Ich habe mich gefragt, ob Sie mehrere upsertsolcher Aktionen in einer Transaktion ausführen können, dh mit der Python- executemany()Funktion.
Radio Controlled
117
INSERT OR IGNORE INTO visits VALUES ($ip, 0);
UPDATE visits SET hits = hits + 1 WHERE ip LIKE $ip;

Dies erfordert, dass die Spalte "ip" eine EINZIGARTIGE (oder PRIMARY KEY) Einschränkung aufweist.


BEARBEITEN: Eine weitere großartige Lösung: https://stackoverflow.com/a/4330694/89771 .

dan04
quelle
2
Nur für die Aufzeichnung REPLACEist keine Option.
Alix Axel
1
In Bezug auf den Link "Eine weitere großartige Lösung" würde ich auch eine andere Antwort auf dieselbe Frage in Betracht
ziehen
19

Ich würde es vorziehen UPDATE (+ INSERT if UPDATE fails). Weniger Code = weniger Fehler.

Codeholic
quelle
1
Vielen Dank! @Sam ( stackoverflow.com/questions/418898/… ) scheint Ihnen zuzustimmen. Ich bevorzuge auch diesen Ansatz.
Alix Axel
@Smith Ich meinte, einfache UPDATE- und INSERT-Anweisungen zu verwenden und den Rückgabewert zu überprüfen.
Codeholic
Dies hat keine Atomizität. Es ist möglich, dass INSERT fehlschlägt, wenn ein anderer Prozess dazwischen eingefügt wird.
Robin Lavallée
7

Die aktuelle Antwort funktioniert nur in SQLite ODER MySQL (je nachdem, ob Sie OR verwenden oder nicht). Wenn Sie also Cross-DBMS-Kompatibilität wünschen, reicht Folgendes aus ...

REPLACE INTO `visits` (ip, value) VALUES ($ip, 0);
Jacob Thomason
quelle
3
Die akzeptierte Antwort funktioniert unter SQLite (das war mein Ziel). REPLACEfunktioniert auch unter SQLite, aber unter MySQL wird der Zähler immer auf 0 zurückgesetzt - während die Abfrage portierbar ist, unterscheidet sich das Endergebnis stark.
Alix Axel
Sie haben Recht, ich dachte, das OP sucht nach etwas, das tragbar ist. Mir ist klar, dass REPLACE INTO nicht in allen Fällen funktioniert, insbesondere wenn eine PK-Aufbewahrung erforderlich ist, aber in vielen Fällen.
Jacob Thomason
Ein fehlerfreier Fehler, anstatt Daten zu verwerfen, ist eine Funktion, kein Fehler.
Tobu
-4

Sie sollten hierfür memcached verwenden, da es sich um einen einzelnen Schlüssel (die IP-Adresse) handelt, in dem ein einzelner Wert (die Anzahl der Besuche) gespeichert ist. Sie können die atomare Inkrementfunktion verwenden, um sicherzustellen, dass keine "Race" -Bedingungen vorliegen.

Es ist schneller als MySQL und spart die Last, sodass sich MySQL auf andere Dinge konzentrieren kann.

Xeoncross
quelle
Wenn die Daten nicht so wichtig sind, ja. Wenn dies jedoch auf einer ausgelasteten Site verwendet wird, auf der viele IP-Adressen den Dienst erreichen, werden die zwischengespeicherten Instanzen möglicherweise voll und führen dazu, dass Inhalte gelöscht werden. Das Sichern von zwischengespeicherten Inhalten wäre ebenfalls interessant (falls erforderlich)
Elliot Foster,
@ElliotFoster Memcached kann so viele Daten verarbeiten wie der RAM, den Sie darauf werfen (wenn Sie auch Ausdauer wünschen, verwenden Sie redis oder membase). Wenn Sie mehr als 1 Million Besucher pro Tag haben, können Sie es sich wahrscheinlich leisten, Ihrer Memcache-Instanz mehr als 30 MB RAM zu geben (was meiner Meinung nach die Standardeinstellung ist). Es kann jedoch mit Sicherheit eine viel höhere Last als SQLite und MySQL für die Menge an Speicher bewältigen, die Sie ihm geben - es gibt einfach keinen Vergleich.
Xeoncross
Bitte verwechseln Sie meinen Kommentar nicht als Abstimmung gegen Memcache, da ich denke, dass dies ein fantastisches Werkzeug ist. Wie Redis (Ich kann nicht für Membase sprechen, da ich es nicht verwendet habe.) Memcache / Redis sind jedoch nicht die zuverlässigsten Speicher. Ja, Redis hat eine Persistenz, aber die Daten bleiben in einem Intervall (zuletzt habe ich nachgesehen) auf der Festplatte erhalten und der Memcache überhaupt nicht. Wie gesagt, wenn die Daten nicht wichtig sind (oder leicht reproduziert werden können), sind Memcache und Firma großartig. Der ursprüngliche Beitrag fragte auch nach SQLite, das sich stark von MySQL unterscheidet und wahrscheinlich bedeutet, dass sie auf andere Weise eingeschränkt sind.
Elliot Foster
Sie können Redis so konfigurieren, dass Daten so schnell wie gewünscht gespeichert werden (bei X Sekunden oder bei Y Anzahl von Änderungen).
Buffalo