SQLite hat den ON CONFLICT -Klausel, mit der Sie angeben können, wie Constraint-Konflikte behandelt werden sollen. Es gilt für UNIQUE , NOT NULL , CHECK , und PRIMARY KEY Beschränkungen (aber nicht FOREIGN KEY Beschränkungen).
Es gibt fünf mögliche Optionen, die Sie mit dieser Klausel verwenden können:
ABORTFAILIGNOREREPLACEROLLBACK
Dieser Artikel enthält Beispiele und Erläuterungen zu jeder dieser Optionen.
Der ON CONFLICT -Klausel wird in CREATE TABLE verwendet -Anweisungen, kann aber auch beim Einfügen oder Aktualisieren von Daten verwendet werden, indem ON CONFLICT ersetzt wird mit OR .
Beim Erstellen der Tabelle
Wie bereits erwähnt, können Sie ON CONFLICT verwenden wenn Sie die Tabelle erstellen oder wenn Sie Daten einfügen/aktualisieren.
Hier ist ein Beispiel für die Verwendung von ON CONFLICT zum Zeitpunkt der Erstellung der Tabelle.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL ON CONFLICT IGNORE,
Price
);
Wenn Sie den ON CONFLICT verwenden -Klausel, wenden Sie sie auf die spezifische Einschränkung an, die Sie behandeln möchten. In diesem Fall habe ich die Klausel zu einem NOT NULL hinzugefügt Einschränkung.
In diesem Fall habe ich IGNORE angegeben , was bedeutet, dass SQLite bei einer Einschränkungsverletzung diese Zeile überspringt und dann mit der Verarbeitung fortfährt.
Wenn ich jetzt versuche, NULL einzufügen in den ProductName Spalte wird diese Zeile übersprungen.
INSERT INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120.0
Beim Einfügen von Daten
Sie können diese Klausel auch beim Einfügen und Aktualisieren von Daten verwenden. Der Unterschied besteht darin, dass Sie ON CONFLICT ersetzen mit OR .
Zur Demonstration lösche ich die vorherige Tabelle und erstelle sie erneut, aber ohne ON CONFLICT Klausel:
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price
);
Jetzt füge ich dieselben Daten ein und verwende OR IGNORE um die Zeile zu überspringen, die gegen die Beschränkung verstößt.
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120.0
Wir erhalten also das gleiche Ergebnis wie im vorherigen Beispiel.
In diesen Beispielen habe ich den IGNORE verwendet Möglichkeit. Dies ist nur eine von fünf möglichen Optionen für diese Klausel.
Unten finden Sie Beispiele, die jede der fünf Optionen verwenden.
Abbruch
Diese Option bricht die aktuelle SQL-Anweisung mit einem SQLITE_CONSTRAINT-Fehler ab und macht alle Änderungen rückgängig, die von der aktuellen SQL-Anweisung vorgenommen wurden; Änderungen, die durch frühere SQL-Anweisungen innerhalb derselben Transaktion verursacht wurden, bleiben jedoch erhalten und die Transaktion bleibt aktiv.
Dies ist das Standardverhalten. Mit anderen Worten, dies passiert bei Verletzungen von Einschränkungen, wenn Sie ON CONFLICT nicht verwenden Klausel.
Hier ist ein Beispiel dafür, was passiert, wenn Sie ABORT angeben .
DELETE FROM Products;
INSERT OR ABORT INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
Es wurden keine Ergebnisse zurückgegeben, weil INSERT Vorgang wurde abgebrochen und die Tabelle ist daher leer.
Folgendes passiert, wenn ich jede Zeile in ein eigenes INSERT setze Anweisung innerhalb einer Transaktion.
BEGIN TRANSACTION;
INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);
INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);
INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120.0
Fehler
Das FAIL Option bricht die aktuelle SQL-Anweisung mit einem SQLITE_CONSTRAINT-Fehler ab. Aber es macht weder frühere Änderungen der fehlgeschlagenen SQL-Anweisung rückgängig, noch beendet es die Transaktion.
Hier ist ein Beispiel.
DELETE FROM Products;
INSERT OR FAIL INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99
Hier geht es mit separatem INSERT rein Anweisungen innerhalb einer Transaktion.
DELETE FROM Products;
BEGIN TRANSACTION;
INSERT OR FAIL INTO Products VALUES (1, 'Hammer', 9.99);
INSERT OR FAIL INTO Products VALUES (2, NULL, 1.49);
INSERT OR FAIL INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR FAIL INTO Products VALUES (4, 'Wrench', 37.00);
INSERT OR FAIL INTO Products VALUES (5, 'Chisel', 23.00);
INSERT OR FAIL INTO Products VALUES (6, 'Bandage', 120.00);
COMMIT;
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120.0
Ignorieren
Das IGNORE Option überspringt die eine Zeile, die die Einschränkungsverletzung enthält, und fährt mit der Verarbeitung nachfolgender Zeilen der SQL-Anweisung fort, als ob nichts schief gegangen wäre. Andere Zeilen vor und nach der Zeile, die die Einschränkungsverletzung enthielt, werden normal eingefügt oder aktualisiert. Für die Eindeutigkeit wird kein Fehler zurückgegeben, NOT NULL , und UNIQUE Beschränkungsfehler, wenn diese Option verwendet wird. Diese Option funktioniert jedoch wie ABORT für Fremdschlüssel-Einschränkungsfehler.
Die ersten Beispiele auf dieser Seite verwenden IGNORE , aber hier ist es noch einmal.
DELETE FROM Products;
INSERT OR IGNORE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, NULL, 1.49),
(3, 'Saw', 11.34),
(4, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Hammer 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120.0
Ersetzen
Das REPLACE Die Option funktioniert je nach Verstoß unterschiedlich:
- Wenn ein
UNIQUEoderPRIMARY KEYEinschränkungsverletzung auftritt,REPLACEOption löscht bereits vorhandene Zeilen, die die Einschränkungsverletzung verursachen, bevor die aktuelle Zeile eingefügt oder aktualisiert wird, und der Befehl wird normal weiter ausgeführt. - Wenn ein
NOT NULLeine Einschränkungsverletzung auftritt, wirdNULLersetzt Wert mit dem Standardwert für diese Spalte, oder wenn die Spalte keinen Standardwert hat, dannABORTAlgorithmus verwendet wird. - Wenn ein
CHECKEinschränkungs- oder Fremdschlüssel-Einschränkungsverletzung auftritt, dannREPLACEfunktioniert wieABORT.
Auch wenn Zeilen gelöscht werden, um eine Einschränkung zu erfüllen, werden Löschtrigger ausgelöst, wenn und nur wenn rekursive Trigger aktiviert sind.
Hier ist ein Beispiel, das den REPLACE verwendet Möglichkeit.
DELETE FROM Products;
INSERT OR REPLACE INTO Products VALUES
(1, 'Hammer', 9.99),
(2, 'Nails', 1.49),
(3, 'Saw', 11.34),
(1, 'Wrench', 37.00),
(5, 'Chisel', 23.00),
(6, 'Bandage', 120.00);
SELECT * FROM Products; Ergebnis:
ProductId Produktname Preis ---------- ----------- ----------1 Schraubenschlüssel 37,0 2 Nägel 1,49 3 Säge 11,34 5 Meißel 23,0 6 Verband 120.0
In diesem Beispiel lag der Konflikt beim Primärschlüssel (ich habe versucht, zwei Zeilen mit derselben ProductId einzufügen ). Das REPLACE Option bewirkte, dass die zweite die erste ersetzte.
Zurücksetzen
Eine weitere Option ist die Verwendung von ROLLBACK .
Diese Option bricht die aktuelle SQL-Anweisung mit einem SQLITE_CONSTRAINT-Fehler ab und setzt die aktuelle Transaktion zurück. Wenn keine Transaktion aktiv ist (außer der impliziten Transaktion, die bei jedem Befehl erstellt wird), funktioniert es genauso wie ABORT Algorithmus.
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', 9.99);
INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);
INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);
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> DELETE FROM Products;sqlite> sqlite> BEGIN TRANSACTION;sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49); Fehler:NOT NULL-Einschränkung fehlgeschlagen:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Fehler:Festschreiben nicht möglich - keine Transaktion ist aktivsqlite> sqlite> SELECT * FROM Produkte;Produkt-ID Produktname Preis ---------- ----------- ----------3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Bandage 120,0Es kam also zur Einschränkungsverletzung und rollte dann die Transaktion zurück. Dann wurden die nachfolgenden Zeilen abgearbeitet und dann das
COMMITSchlü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', 9.99); INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49); INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34); INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00); 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', 9.99);sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);Fehler:NOT NULL Einschränkung failed:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);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 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120,0In diesem Fall funktionierte es wie
ABORT.Zur Bestätigung hier die gleiche Anweisung mit
ABORTstattROLLBACK.DELETE FROM Products; INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99); INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49); INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34); INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00); 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', 9.99);sqlite> INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);Fehler:NOT NULL Einschränkung fehlgeschlagen:Products.ProductNamesqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);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 9,99 3 Säge 11,34 4 Schraubenschlüssel 37,0 5 Meißel 23,0 6 Verband 120,0