SQLite hat eine nicht standardmäßige SQL-Erweiterungsklausel namens ON CONFLICT
Dadurch können wir angeben, wie mit Constraint-Konflikten umgegangen werden soll.
Insbesondere gilt die Klausel für UNIQUE
, NOT NULL
, CHECK
, und PRIMARY KEY
Einschränkungen.
Dieser Artikel enthält Beispiele dafür, wie diese Klausel verwendet werden kann, um zu bestimmen, wie Konflikte mit Primärschlüsseleinschränkungen behandelt werden.
Mit „Primärschlüssel-Einschränkungskonflikten“ meine ich, wenn Sie versuchen, einen doppelten Wert in eine Primärschlüsselspalte einzufügen. Wenn Sie dies versuchen, wird die Operation standardmäßig abgebrochen und SQLite gibt einen Fehler zurück.
Aber Sie können den ON CONFLICT
verwenden -Klausel, um die Art und Weise zu ändern, wie SQLite mit diesen Situationen umgeht.
Eine Möglichkeit besteht darin, diese Klausel in CREATE TABLE
zu verwenden Anweisung beim Erstellen der Tabelle. Dadurch wird bestimmt, wie alle INSERT
Operationen behandelt werden.
Eine andere Möglichkeit besteht darin, die Klausel auf dem INSERT
zu verwenden -Anweisung, wenn Sie versuchen, Daten in die Tabelle einzufügen. Dadurch können Sie die Klausel nutzen, auch wenn die Tabelle nicht damit erstellt wurde. Wenn Sie diese Option verwenden, ist die Syntax anders; Sie verwenden OR
statt ON CONFLICT
.
Die Beispiele auf dieser Seite verwenden die zweite Option – ich erstelle die Tabelle ohne der ON CONFLICT
-Klausel, und ich gebe stattdessen OR
an auf INSERT
Erklärung.
Beispieltabelle
Lassen Sie uns eine einfache Tabelle erstellen und eine Zeile hinzufügen.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName,
Price
);
INSERT INTO Products VALUES (1, 'Hammer', 8.00);
SELECT * FROM Products;
Ergebnis:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Wir haben derzeit eine Zeile mit einer ProductId von 1 .
Jetzt können wir die verschiedenen Szenarien zum Einfügen von Daten in diese Tabelle durchgehen, die gegen die Primärschlüsseleinschränkung verstoßen.
Beispiel 1 – Abbrechen (Standardverhalten)
Wie bereits erwähnt, besteht das Standardverhalten von SQLite darin, INSERT
abzubrechen ausführen und einen Fehler zurückgeben.
INSERT INTO Products VALUES (1, 'Wrench', 12.50);
Ergebnis:
Error: UNIQUE constraint failed: Products.ProductId
Es wurde ein Fehler zurückgegeben und es wurde nichts eingefügt.
Dies entspricht der Verwendung von OR ABORT
Option.
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);
Ergebnis:
Error: UNIQUE constraint failed: Products.ProductId
Wir können überprüfen, ob nichts eingefügt wurde, indem wir ein SELECT
ausführen Aussage gegen die Tabelle.
SELECT * FROM Products;
Ergebnis:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Wir können sehen, dass die Tabelle nur die ursprüngliche Zeile enthält.
Beispiel 2 – Ignorieren
Eine Alternative besteht darin, SQLite die anstößige Zeile ignorieren zu lassen. Mit anderen Worten, es überspringt die Zeile und fährt mit der Verarbeitung nachfolgender Zeilen fort.
Dazu innerhalb Ihres INSERT
-Anweisung verwenden Sie OR IGNORE
.
Dies hat zur Folge, dass der INSERT
Der Vorgang ist erfolgreich, aber ohne Zeilen, die gegen die Primärschlüsseleinschränkung verstoßen.
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 12.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Ergebnis:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
In diesem Fall habe ich versucht, zwei neue Zeilen mit einer ID einzufügen, die bereits in der Tabelle vorhanden war, also wurden diese beiden Zeilen übersprungen.
Beispiel 3 – Ersetzen
Eine weitere Option besteht darin, die ursprüngliche Zeile durch die neue Zeile zu ersetzen.
Mit anderen Worten, Sie überschreiben die vorhandenen Daten mit Ihren neuen Daten.
Verwenden Sie dazu OR REPLACE
.
INSERT OR REPLACE INTO Products VALUES
(1, 'Hammer', 12.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Ergebnis:
ProductId ProductName Price ---------- ----------- ---------- 1 Wrench 22.5 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
In diesem Fall waren die meisten Zeilen gleich, also enthalten sie nach dem INSERT
die gleichen Daten Betrieb. Wir können jedoch sehen, dass die erste Zeile aktualisiert wurde, um die Werte in meinem INSERT
zu verwenden Erklärung.
Wir können auch sehen, dass es den zweiten Satz von Werten verwendet hat (da zwei die gleiche ProductId teilen). ).
Der Effekt ist also so etwas wie ein UPDATE
-Anweisung und INSERT
Anweisung kombiniert.
Beispiel 4 – Rollback
Eine weitere Möglichkeit ist die Verwendung des ROLLBACK
Option.
Dadurch wird die aktuelle SQL-Anweisung mit einem SQLITE_CONSTRAINT-Fehler abgebrochen und die aktuelle Transaktion zurückgesetzt. Wenn keine Transaktion aktiv ist (außer der impliziten Transaktion, die bei jedem Befehl erstellt wird), funktioniert es genauso wie ABORT
Algorithmus.
Es lohnt sich, darauf zu achten, wie diese Option funktioniert. Hier ist ein Beispiel, das mehrere INSERT OR ROLLBACK
verwendet Anweisungen innerhalb einer Transaktion.
DELETE FROM Products;
BEGIN TRANSACTION;
INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products;
Hier ist die vollständige Ausgabe von meinem Terminal, wenn ich dies ausführe:
sqlite> BEGIN TRANSACTION; sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00); sqlite> COMMIT; Error: cannot commit - no transaction is active sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 5 Chisel 23.0 6 Bandage 120.0 sqlite>
Was hier im Grunde passiert ist, ist, dass es bis zur Einschränkungsverletzung gekommen ist und dann die Transaktion zurückgesetzt hat. Dann wurden die nächsten beiden Zeilen abgearbeitet und dann das COMMIT
Schlüsselwort gefunden. Zu diesem Zeitpunkt war die Transaktion bereits zurückgesetzt worden, und wir erhielten einen weiteren Fehler, der uns mitteilte, dass keine Transaktion aktiv war.
Folgendes passiert, wenn ich es aus der Transaktion entferne.
DELETE FROM Products;
INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
SELECT * FROM Products;
Hier ist die vollständige Ausgabe von meinem Terminal, wenn ich dies ausführe:
sqlite> DELETE FROM Products; sqlite> sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00); sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0 sqlite>
In diesem Fall funktionierte es wie ABORT
.
Um dies zu demonstrieren, hier die gleiche Anweisung mit ABORT
statt ROLLBACK
.
DELETE FROM Products;
INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
SELECT * FROM Products;
Hier ist die vollständige Ausgabe von meinem Terminal, wenn ich dies ausführe:
sqlite> DELETE FROM Products; sqlite> sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00); sqlite> INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50); sqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50); sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50); Error: UNIQUE constraint failed: Products.ProductId sqlite> INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00); sqlite> INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00); sqlite> sqlite> SELECT * FROM Products; ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0 sqlite>
Die Fehleroption
Das FAIL
Option bricht die aktuelle SQL-Anweisung mit einem SQLITE_CONSTRAINT-Fehler ab. Aber diese Option macht weder frühere Änderungen der fehlgeschlagenen SQL-Anweisung rückgängig, noch beendet sie die Transaktion.
DELETE FROM Products;
INSERT OR FAIL INTO Products VALUES
(1, 'Hammer', 8.00),
(2, 'Nails', 2.50),
(3, 'Saw', 10.50),
(1, 'Wrench', 22.50),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products;
Ergebnis:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5