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
ofPRIMARY KEY
beperkingsschending optreedt,, deREPLACE
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 deNULL
waarde met de standaardwaarde voor die kolom, of als de kolom geen standaardwaarde heeft, dan deABORT
algoritme wordt gebruikt. - Als een
CHECK
beperking of schending van de externe sleutelbeperking optreedt, danREPLACE
werkt alsABORT
.
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