sql >> Database >  >> RDS >> SQLite

Omgaan met primaire sleutelconflicten bij het invoegen van gegevens in SQLite

SQLite heeft een niet-standaard SQL-extensieclausule genaamd ON CONFLICT dat stelt ons in staat om te specificeren hoe om te gaan met beperkingsconflicten.

De clausule is in het bijzonder van toepassing op UNIQUE , NOT NULL , CHECK , en PRIMARY KEY beperkingen.

Dit artikel bevat voorbeelden van hoe deze clausule kan worden gebruikt om te bepalen hoe conflicten met primaire sleutelbeperkingen moeten worden afgehandeld.

Met "conflicten met primaire sleutelbeperkingen" bedoel ik wanneer u een dubbele waarde in een primaire sleutelkolom probeert in te voegen. Wanneer u dit probeert te doen, wordt de bewerking standaard afgebroken en geeft SQLite een foutmelding.

Maar je kunt de ON CONFLICT . gebruiken clausule om de manier waarop SQLite met deze situaties omgaat te veranderen.

Een optie is om deze clausule te gebruiken in de CREATE TABLE verklaring bij het maken van de tabel. Als u dat doet, wordt bepaald hoe alle INSERT operaties worden behandeld.

Een andere optie is om de clausule op de INSERT . te gebruiken telkens wanneer u gegevens in de tabel probeert in te voegen. Hierdoor kunt u profiteren van de clausule, zelfs als de tabel er niet mee is gemaakt. Wanneer u deze optie gebruikt, is de syntaxis anders; je gebruikt OR in plaats van ON CONFLICT .

De voorbeelden op deze pagina gebruiken de tweede optie – ik maak de tabel zonder de ON CONFLICT clausule, en ik specificeer in plaats daarvan OR op de INSERT verklaring.

Voorbeeldtabel

Laten we een eenvoudige tabel maken en één rij toevoegen.

CREATE TABLE Products( 
    ProductId INTEGER PRIMARY KEY, 
    ProductName, 
    Price
);

INSERT INTO Products VALUES (1, 'Hammer', 8.00);

SELECT * FROM Products;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       

We hebben momenteel één rij, met een ProductId van 1 .

Nu kunnen we de verschillende scenario's doorlopen voor het invoegen van gegevens in die tabel die de primaire sleutelbeperking schenden.

Voorbeeld 1 – Afbreken (standaardgedrag)

Zoals vermeld, is het standaardgedrag voor SQLite het afbreken van de INSERT bewerking en retourneert een fout.

INSERT INTO Products VALUES (1, 'Wrench', 12.50);

Resultaat:

Error: UNIQUE constraint failed: Products.ProductId

Er is een fout geretourneerd en er is niets ingevoegd.

Dit is het equivalent van het gebruik van de OR ABORT optie.

INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);

Resultaat:

Error: UNIQUE constraint failed: Products.ProductId

We kunnen controleren of er niets is ingevoegd door een SELECT . uit te voeren verklaring tegen de tafel.

SELECT * FROM Products;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       

We kunnen zien dat de tabel alleen de originele rij bevat.

Voorbeeld 2 – Negeren

Een alternatief is om SQLite de beledigende rij te laten negeren. Met andere woorden, het zal de rij overslaan en doorgaan met het verwerken van volgende rijen.

Om dit te doen binnen uw INSERT instructie, gebruik OR IGNORE .

Het effect hiervan is dat de INSERT bewerking slaagt, maar zonder rijen die de primaire sleutelbeperking schenden.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     

In dit geval heb ik geprobeerd twee nieuwe rijen in te voegen met een ID die al in de tabel bestond, dus beide rijen werden overgeslagen.

Voorbeeld 3 – Vervangen

Een andere optie die je hebt is om de originele rij te vervangen door de nieuwe rij.

Met andere woorden, u overschrijft de bestaande gegevens met uw nieuwe gegevens.

Gebruik hiervoor 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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Wrench       22.5      
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     

In dit geval waren de meeste rijen hetzelfde, dus bevatten ze dezelfde gegevens na de INSERT operatie. We kunnen echter zien dat de eerste rij is bijgewerkt om de waarden in mijn INSERT . te gebruiken uitspraak.

We kunnen ook zien dat het de tweede set waarden gebruikte (aangezien twee dezelfde ProductId delen) ).

Het effect is dus een soort UPDATE statement en INSERT verklaring gecombineerd.

Voorbeeld 4 – Terugdraaien

Een andere optie is om de ROLLBACK . te gebruiken optie.

Hierdoor wordt de huidige SQL-instructie afgebroken met een SQLITE_CONSTRAINT-fout en wordt de huidige transactie teruggedraaid. Als er geen transactie actief is (behalve de impliciete transactie die bij elke opdracht wordt gemaakt), werkt het hetzelfde als de ABORT algoritme.

Het loont de moeite om bewust te zijn van hoe deze optie werkt. Hier is een voorbeeld dat gebruik maakt van meerdere INSERT OR ROLLBACK afschriften binnen een transactie.

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 is de volledige uitvoer van mijn terminal wanneer ik dit uitvoer:

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> 

Wat hier in feite is gebeurd, is dat het zover is gekomen als de schending van de beperking en vervolgens de transactie heeft teruggedraaid. Vervolgens werden de volgende twee regels verwerkt en vervolgens de COMMIT trefwoord is aangetroffen. Tegen die tijd was de transactie al teruggedraaid en kregen we dus nog een foutmelding dat er geen transactie actief was.

Dit is wat er gebeurt als ik het uit de transactie verwijder.

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 is de volledige uitvoer van mijn terminal wanneer ik dit uitvoer:

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 dit geval werkte het als ABORT .

Om dit aan te tonen, volgt hier dezelfde verklaring met ABORT in plaats van 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 is de volledige uitvoer van mijn terminal wanneer ik dit uitvoer:

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> 

De Fail-optie

De FAIL optie breekt de huidige SQL-instructie af met een SQLITE_CONSTRAINT-fout. Maar met deze optie worden eerdere wijzigingen van de mislukte SQL-instructie niet ongedaan gemaakt en wordt de transactie ook niet beëindigd.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      

  1. Een Peer-to-Peer Lending Platform-gegevensmodel

  2. wat is een goede manier om horizontale scherf in postgresql te plaatsen?

  3. Verschil tussen sleutel, primaire sleutel, unieke sleutel en index in MySQL

  4. MariaDB DEFAULT() Uitgelegd