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:
ABORT
FAIL
IGNORE
REPLACE
ROLLBACK
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
UNIQUE
oderPRIMARY KEY
Einschränkungsverletzung auftritt,REPLACE
Option 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 NULL
eine Einschränkungsverletzung auftritt, wirdNULL
ersetzt Wert mit dem Standardwert für diese Spalte, oder wenn die Spalte keinen Standardwert hat, dannABORT
Algorithmus verwendet wird. - Wenn ein
CHECK
Einschränkungs- oder Fremdschlüssel-Einschränkungsverletzung auftritt, dannREPLACE
funktioniert 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
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', 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
ABORT
stattROLLBACK
.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