Ich habe einige "wäre" -Lösungen für den Klassiker "Wie füge ich einen neuen Datensatz ein oder aktualisiere einen, wenn er bereits vorhanden ist" gefunden, aber ich kann keine davon in SQLite zum Laufen bringen.
Ich habe eine Tabelle wie folgt definiert:
CREATE TABLE Book
ID INTEGER PRIMARY KEY AUTOINCREMENT,
Name VARCHAR(60) UNIQUE,
TypeID INTEGER,
Level INTEGER,
Seen INTEGER
Ich möchte einen Datensatz mit einem eindeutigen Namen hinzufügen. Wenn der Name bereits vorhanden ist, möchte ich die Felder ändern.
Kann mir bitte jemand sagen, wie das geht?
Antworten:
Schauen Sie sich http://sqlite.org/lang_conflict.html an .
Du willst so etwas wie:
Beachten Sie, dass jedes Feld, das nicht in der Einfügeliste enthalten ist, auf NULL gesetzt wird, wenn die Zeile bereits in der Tabelle vorhanden ist. Aus diesem Grund gibt es eine Unterauswahl für die
ID
Spalte: Im Ersatzfall würde die Anweisung sie auf NULL setzen und dann würde eine neue ID zugewiesen.Dieser Ansatz kann auch verwendet werden, wenn Sie bestimmte Feldwerte in Ruhe lassen möchten, wenn die Zeile im Ersetzungsfall, aber das Feld im Einfügefall auf NULL gesetzt wird.
Angenommen, Sie möchten in
Seen
Ruhe lassen:quelle
Level
kann dieser Ansatz nicht befolgt werden.Sie sollten den
INSERT OR IGNORE
Befehl gefolgt von einemUPDATE
Befehl verwenden: Im folgenden Beispielname
ist ein Primärschlüssel:Der erste Befehl fügt den Datensatz ein. Wenn der Datensatz vorhanden ist, wird der Fehler ignoriert, der durch den Konflikt mit einem vorhandenen Primärschlüssel verursacht wurde.
Der zweite Befehl aktualisiert den Datensatz (der jetzt definitiv existiert).
quelle
Sie müssen eine Einschränkung für die Tabelle festlegen, um einen " Konflikt " auszulösen, den Sie dann durch Ersetzen lösen:
Dann können Sie Folgendes ausgeben:
Die "SELECT * FROM Daten" geben Ihnen:
Beachten Sie, dass die data.id "3" und nicht "1" ist, da REPLACE ein DELETE und INSERT ausführt, kein UPDATE. Dies bedeutet auch, dass Sie sicherstellen müssen, dass Sie alle erforderlichen Spalten definieren, da sonst unerwartete NULL-Werte angezeigt werden.
quelle
Aktualisieren Sie es zuerst. Wenn die Anzahl der betroffenen Zeilen = 0 ist, fügen Sie sie ein. Es ist das einfachste und für alle RDBMS geeignete .
quelle
Insert or Replace
ist wirklich vorzuziehen.INSERT OR REPLACE
ersetzt die anderen Felder auf den Standardwert.Wenn Sie das andere Feld beibehalten möchten
oder mit UPSERT (Syntax wurde SQLite mit Version 3.24.0 (2018-06-04) hinzugefügt)
Das
excluded.
Präfix entspricht dem Wert inVALUES
.quelle
Upsert ist was du willst.
UPSERT
Die Syntax wurde zu SQLite mit Version 3.24.0 (2018-06-04) hinzugefügt.Seien Sie gewarnt, dass an dieser Stelle das eigentliche Wort "UPSERT" nicht Teil der Upsert-Syntax ist.
Die richtige Syntax lautet
INSERT INTO ... ON CONFLICT(...) DO UPDATE SET...
und wenn Sie
INSERT INTO SELECT ...
Ihre Auswahl treffen, müssen Sie zumindestWHERE true
die Parser-Mehrdeutigkeit bezüglich des TokensON
mit der Join-Syntax lösen .Seien Sie gewarnt, dass
INSERT OR REPLACE...
der Datensatz vor dem Einfügen eines neuen Datensatzes gelöscht wird, wenn er ersetzt werden muss. Dies kann schlecht sein, wenn Sie Fremdschlüsselkaskaden oder andere Löschauslöser haben.quelle
UPSERT
Syntax nicht unterstützt .Wenn Sie keinen Primärschlüssel haben, können Sie ihn einfügen, falls er nicht vorhanden ist, und dann ein Update durchführen. Die Tabelle muss mindestens einen Eintrag enthalten, bevor Sie diesen verwenden können.
quelle
Ich glaube du willst UPSERT .
"EINFÜGEN ODER ERSETZEN" ohne den zusätzlichen Trick in dieser Antwort setzt alle Felder, die Sie nicht angeben, auf NULL oder einen anderen Standardwert zurück. (Dieses Verhalten von INSERT OR REPLACE unterscheidet sich von UPDATE. Es ist genau wie INSERT, da es tatsächlich INSERT ist. Wenn Sie jedoch UPDATE-if-exist möchten, möchten Sie wahrscheinlich die UPDATE-Semantik und werden vom tatsächlichen Ergebnis unangenehm überrascht sein.)
Der Trick bei der vorgeschlagenen UPSERT-Implementierung besteht im Wesentlichen darin, INSERT OR REPLACE zu verwenden, aber alle Felder mit eingebetteten SELECT-Klauseln anzugeben, um den aktuellen Wert für Felder abzurufen, die Sie nicht ändern möchten.
quelle
Ich denke, es ist erwähnenswert, dass es hier zu unerwartetem Verhalten kommen kann, wenn Sie nicht genau verstehen, wie PRIMARY KEY und UNIQUE interagieren.
Wenn Sie beispielsweise einen Datensatz nur einfügen möchten, wenn das Feld NAME derzeit nicht verwendet wird, und wenn dies der Fall ist, möchten Sie, dass eine Einschränkungsausnahme ausgelöst wird , wird INSERT OR REPLACE keine Ausnahme auslösen und stattdessen Lösen Sie die EINZIGARTIGE Einschränkung selbst, indem Sie den widersprüchlichen Datensatz (den vorhandenen Datensatz mit demselben NAMEN ) ersetzen . Gaspard's zeigt dies sehr gut in seiner obigen Antwort .
Wenn eine Einschränkungsausnahme ausgelöst werden soll, müssen Sie eine INSERT- Anweisung verwenden und sich auf einen separaten UPDATE- Befehl verlassen, um den Datensatz zu aktualisieren, sobald Sie wissen, dass der Name nicht verwendet wird.
quelle