sql >> Database >  >> RDS >> SQLite

Hoe ON CONFLICT werkt in SQLite

SQLite heeft de ON CONFLICT clausule waarmee u kunt specificeren hoe beperkingsconflicten moeten worden afgehandeld. Het is van toepassing op UNIQUE , NOT NULL , CHECK , en PRIMARY KEY beperkingen (maar niet FOREIGN KEY beperkingen).

Er zijn vijf mogelijke opties die u met deze clausule kunt gebruiken:

  • ABORT
  • FAIL
  • IGNORE
  • REPLACE
  • ROLLBACK

Dit artikel geeft voorbeelden en een uitleg van elk van deze opties.

De ON CONFLICT clausule wordt gebruikt in CREATE TABLE instructies, maar het kan ook worden gebruikt bij het invoegen of bijwerken van gegevens door ON CONFLICT te vervangen met OR .

Bij het maken van de tabel

Zoals vermeld, kunt u ON CONFLICT . gebruiken wanneer u de tabel maakt of wanneer u gegevens invoegt/bijwerkt.

Hier is een voorbeeld van het gebruik van ON CONFLICT op het moment van het maken van de tafel.

CREATE TABLE Products( 
    ProductId INTEGER PRIMARY KEY, 
    ProductName NOT NULL ON CONFLICT IGNORE, 
    Price
);

Wanneer u de ON CONFLICT . gebruikt clausule, past u deze toe op de specifieke beperking die u wilt behandelen. In dit geval heb ik de clausule toegevoegd aan een NOT NULL beperking.

In dit geval heb ik IGNORE opgegeven , wat betekent dat, als er een schending van een beperking is, SQLite die rij overslaat en vervolgens doorgaat met verwerken.

Als ik nu NULL probeer in te voegen, in de Productnaam kolom die rij wordt overgeslagen.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Bij het invoegen van gegevens

U kunt deze clausule ook gebruiken bij het invoeren en bijwerken van gegevens. Het verschil is dat je ON CONFLICT . vervangt met OR .

Om te demonstreren, zal ik de vorige tabel laten vallen en opnieuw maken, maar zonder de ON CONFLICT clausule:

DROP TABLE IF EXISTS Products;

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

Nu voeg ik dezelfde gegevens in en gebruik OR IGNORE om de rij over te slaan die de beperking schendt.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

We krijgen dus hetzelfde resultaat als in het vorige voorbeeld.

In deze voorbeelden heb ik de IGNORE . gebruikt optie. Dit is slechts een van de vijf mogelijke opties voor deze clausule.

Hieronder staan ​​voorbeelden waarin elk van de vijf opties wordt gebruikt.

Afbreken

Met deze optie wordt de huidige SQL-instructie afgebroken met een SQLITE_CONSTRAINT-fout en worden alle wijzigingen die door de huidige SQL-instructie zijn aangebracht, ongedaan gemaakt; maar wijzigingen veroorzaakt door eerdere SQL-instructies binnen dezelfde transactie blijven behouden en de transactie blijft actief.

Dit is het standaardgedrag. Met andere woorden, dit is wat er gebeurt tijdens beperkingsschendingen wanneer u de ON CONFLICT niet gebruikt clausule.

Hier is een voorbeeld van wat er gebeurt als je ABORT opgeeft .

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;

Resultaat:

 

Er zijn geen resultaten geretourneerd omdat de INSERT bewerking is afgebroken en de tabel is daarom leeg.

Dit is wat er gebeurt als ik elke rij in zijn eigen INSERT plaats afschrift binnen een transactie.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Mislukt

De FAIL optie breekt de huidige SQL-instructie af met een SQLITE_CONSTRAINT-fout. Maar het maakt eerdere wijzigingen van de SQL-instructie die mislukt is niet ongedaan, noch beëindigt het de transactie.

Hier is een voorbeeld.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      

Hier is het met aparte INSERT afschriften binnen een transactie.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Negeren

De IGNORE optie slaat de ene rij over die de schending van de beperking bevat en gaat door met het verwerken van de volgende rijen van de SQL-instructie alsof er niets mis is gegaan. Andere rijen voor en na de rij die de beperkingsschending bevatte, worden normaal ingevoegd of bijgewerkt. Er wordt geen fout geretourneerd voor uniciteit, NOT NULL , en UNIQUE beperkingsfouten wanneer deze optie wordt gebruikt. Deze optie werkt echter als ABORT voor fouten met externe sleutelbeperkingen.

De eerste voorbeelden op deze pagina gebruiken IGNORE , maar hier is het weer.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Vervangen

De REPLACE optie werkt anders, afhankelijk van de overtreding:

  • Als een UNIQUE of PRIMARY KEY beperkingsschending optreedt,, de REPLACE optie verwijdert reeds bestaande rijen die de beperkingsschending veroorzaken voordat de huidige rij wordt ingevoegd of bijgewerkt en de opdracht wordt normaal uitgevoerd.
  • Als een NOT NULL beperkingsschending optreedt, vervangt het de NULL waarde met de standaardwaarde voor die kolom, of als de kolom geen standaardwaarde heeft, dan de ABORT algoritme wordt gebruikt.
  • Als een CHECK beperking of schending van de externe sleutelbeperking optreedt, dan REPLACE werkt als ABORT .

Als het rijen verwijdert om aan een beperking te voldoen, worden verwijdertriggers geactiveerd als en alleen als recursieve triggers zijn ingeschakeld.

Hier is een voorbeeld dat de REPLACE . gebruikt optie.

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;

Resultaat:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Wrench       37.0      
2           Nails        1.49      
3           Saw          11.34     
5           Chisel       23.0      
6           Bandage      120.0     

In dit voorbeeld was het conflict met de primaire sleutel (ik heb geprobeerd twee rijen in te voegen met dezelfde ProductId ). De REPLACE optie zorgde ervoor dat de tweede de eerste verving.

Terugdraaien

Een andere optie is om ROLLBACK . te gebruiken .

Met deze optie wordt de huidige SQL-instructie met een SQLITE_CONSTRAINT-fout afgebroken 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.

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

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);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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;
Error: cannot commit - no transaction is active
sqlite>   
sqlite> SELECT * FROM Products;
ProductId   ProductName  Price     
----------  -----------  ----------
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Dus het kwam tot de beperkingsschending en rolde vervolgens de transactie terug. Vervolgens werden de volgende 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', 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 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', 9.99);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

In dit geval werkte het als ABORT .

Ter bevestiging, hier is dezelfde verklaring met ABORT in plaats van 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 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', 9.99);
sqlite> INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     


  1. Een string invoegen die een &bevat

  2. C#:een door de gebruiker gedefinieerd type doorgeven aan een opgeslagen procedure van Oracle

  3. Hoe MySQL op CentOS te upgraden

  4. Prestaties en prijzen van PostgreSQL DigitalOcean vergelijken - ScaleGrid versus door DigitalOcean beheerde databases