SQLite
 sql >> Datenbank >  >> RDS >> SQLite

Funktionsweise von ON CONFLICT in SQLite

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 oder PRIMARY 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, wird NULL ersetzt Wert mit dem Standardwert für diese Spalte, oder wenn die Spalte keinen Standardwert hat, dann ABORT Algorithmus verwendet wird.
  • Wenn ein CHECK Einschränkungs- oder Fremdschlüssel-Einschränkungsverletzung auftritt, dann REPLACE funktioniert wie ABORT .

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,0  

Es 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,0 

In diesem Fall funktionierte es wie ABORT .

Zur Bestätigung hier die gleiche Anweisung mit ABORT statt ROLLBACK .

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