SQLite har en ikke-standard SQL-udvidelsesklausul kaldet ON CONFLICT
der sætter os i stand til at specificere, hvordan vi skal håndtere begrænsningskonflikter.
Især gælder klausulen for UNIQUE
, NOT NULL
, CHECK
og PRIMARY KEY
begrænsninger.
Denne artikel giver eksempler på, hvordan denne klausul kan bruges til at bestemme, hvordan man håndterer primærnøglekonflikter.
Med "primære nøglekonflikter" mener jeg, når du forsøger at indsætte en dubletværdi i en primærnøglekolonne. Som standard, når du prøver at gøre dette, vil handlingen blive afbrudt, og SQLite vil returnere en fejl.
Men du kan bruge ON CONFLICT
klausul for at ændre den måde, SQLite håndterer disse situationer på.
En mulighed er at bruge denne klausul i CREATE TABLE
udsagn, når du laver tabellen. Hvis du gør det, vil det afgøre, hvordan alle INSERT
operationer behandles.
En anden mulighed er at bruge klausulen på INSERT
sætning, når du forsøger at indsætte data i tabellen. Dette giver dig mulighed for at drage fordel af klausulen, selv når tabellen ikke blev oprettet med den. Når du bruger denne mulighed, er syntaksen anderledes; du bruger OR
i stedet for ON CONFLICT
.
Eksemplerne på denne side bruger den anden mulighed – jeg opretter tabellen uden koden ON CONFLICT
klausul, og jeg angiver i stedet OR
på INSERT
erklæring.
Eksempeltabel
Lad os oprette en simpel tabel og tilføje en række.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName,
Price
);
INSERT INTO Products VALUES (1, 'Hammer', 8.00);
SELECT * FROM Products;
Resultat:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Vi har i øjeblikket én række med et ProductId af 1 .
Nu kan vi gennemgå de forskellige scenarier med indsættelse af data i den tabel, der overtræder den primære nøglebegrænsning.
Eksempel 1 – Afbryd (standardadfærd)
Som nævnt er standardadfærden for SQLite at afbryde INSERT
operation og returnerer en fejl.
INSERT INTO Products VALUES (1, 'Wrench', 12.50);
Resultat:
Error: UNIQUE constraint failed: Products.ProductId
Der blev returneret en fejl, og der blev ikke indsat noget.
Dette svarer til at bruge OR ABORT
mulighed.
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);
Resultat:
Error: UNIQUE constraint failed: Products.ProductId
Vi kan bekræfte, at intet blev indsat ved at køre en SELECT
udsagn mod bordet.
SELECT * FROM Products;
Resultat:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0
Vi kan se, at tabellen kun indeholder den oprindelige række.
Eksempel 2 – Ignorer
Et alternativ er at få SQLite til at ignorere den stødende række. Med andre ord vil den springe over rækken og fortsætte med at behandle efterfølgende rækker.
For at gøre dette i din INSERT
sætning, brug OR IGNORE
.
Effekten af dette er, at INSERT
handlingen lykkes, men uden nogen rækker, der overtræder den primære nøglebegrænsning.
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;
Resultat:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
I dette tilfælde forsøgte jeg at indsætte to nye rækker med et ID, der allerede fandtes i tabellen, så begge disse rækker blev sprunget over.
Eksempel 3 – Erstat
En anden mulighed, du har, er at erstatte den oprindelige række med den nye række.
Du vil med andre ord overskrive de eksisterende data med dine nye data.
For at gøre dette skal du bruge 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;
Resultat:
ProductId ProductName Price ---------- ----------- ---------- 1 Wrench 22.5 2 Nails 2.5 3 Saw 10.5 5 Chisel 23.0 6 Bandage 120.0
I dette tilfælde var de fleste rækker de samme, så de indeholder de samme data efter INSERT
operation. Vi kan dog se, at den første række er blevet opdateret til at bruge værdierne i min INSERT
udmelding.
Vi kan også se, at den brugte det andet sæt værdier (eftersom to delte det samme ProductId ).
Så effekten er lidt ligesom en UPDATE
sætning og INSERT
erklæring kombineret.
Eksempel 4 – Tilbageførsel
En anden mulighed er at bruge ROLLBACK
mulighed.
Dette afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl og ruller den aktuelle transaktion tilbage. Hvis ingen transaktion er aktiv (ud over den underforståede transaktion, der oprettes på hver kommando), fungerer den på samme måde som ABORT
algoritme.
Det betaler sig at være opmærksom på, hvordan denne mulighed fungerer. Her er et eksempel, der bruger flere INSERT OR ROLLBACK
opgørelser inden for en 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;
Her er det fulde output fra min terminal, når jeg kører dette:
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>
Grundlæggende er det, der skete her, at det er nået så langt som overtrædelsen af begrænsningen, og derefter rullede transaktionen tilbage. Derefter blev de næste to linjer behandlet og derefter COMMIT
søgeord blev stødt på. På det tidspunkt var transaktionen allerede blevet rullet tilbage, så vi fik endnu en fejl, der fortalte os, at ingen transaktion var aktiv.
Her er, hvad der sker, hvis jeg fjerner det fra transaktionen.
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;
Her er det fulde output fra min terminal, når jeg kører dette:
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>
I dette tilfælde virkede det som ABORT
.
For at demonstrere dette, her er den samme erklæring ved hjælp af ABORT
i stedet for 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;
Her er det fulde output fra min terminal, når jeg kører dette:
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>
Fejlmuligheden
FAIL
option afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl. Men denne mulighed trækker ikke tilbage tidligere ændringer af SQL-sætningen, der mislykkedes, og den afslutter heller ikke transaktionen.
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;
Resultat:
ProductId ProductName Price ---------- ----------- ---------- 1 Hammer 8.0 2 Nails 2.5 3 Saw 10.5