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

Umgang mit Primärschlüsselkonflikten beim Einfügen von Daten in SQLite

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