SQLite har ON CONFLICT
klausul, der giver dig mulighed for at specificere, hvordan begrænsningskonflikter skal håndteres. Det gælder for UNIQUE
, NOT NULL
, CHECK
og PRIMARY KEY
begrænsninger (men ikke FOREIGN KEY
begrænsninger).
Der er fem mulige muligheder, du kan bruge med denne klausul:
ABORT
FAIL
IGNORE
REPLACE
ROLLBACK
Denne artikel giver eksempler og en forklaring på hver af disse muligheder.
ON CONFLICT
klausul bruges i CREATE TABLE
sætninger, men det kan også bruges ved indsættelse eller opdatering af data ved at erstatte ON CONFLICT
med OR
.
Når du opretter tabellen
Som nævnt kan du bruge ON CONFLICT
når du opretter tabellen, eller når du indsætter/opdaterer data.
Her er et eksempel på brug af ON CONFLICT
på tidspunktet for oprettelse af tabellen.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL ON CONFLICT IGNORE,
Price
);
Når du bruger ON CONFLICT
klausul, anvender du den til den specifikke begrænsning, du vil håndtere. I dette tilfælde tilføjede jeg klausulen til en NOT NULL
begrænsning.
I dette tilfælde specificerede jeg IGNORE
, hvilket betyder, at hvis der er en overtrædelse af en begrænsning, vil SQLite springe over den række og derefter fortsætte behandlingen.
Hvis jeg nu prøver at indsætte NULL
ind i Produktnavn kolonne, den række springes over.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0
Når du indsætter data
Du kan også bruge denne klausul, når du indsætter og opdaterer data. Forskellen er, at du erstatter ON CONFLICT
med OR
.
For at demonstrere vil jeg droppe den forrige tabel og oprette den igen, men uden ON CONFLICT
klausul:
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price
);
Nu vil jeg indsætte de samme data og bruge OR IGNORE
for at springe over den række, der overtræder begrænsningen.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0
Så vi får det samme resultat som i det foregående eksempel.
I disse eksempler brugte jeg IGNORE
mulighed. Dette er blot en af fem mulige muligheder for denne klausul.
Nedenfor er eksempler, der bruger hver af de fem muligheder.
Afbryd
Denne indstilling afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl og fjerner eventuelle ændringer foretaget af den aktuelle SQL-sætning; men ændringer forårsaget af tidligere SQL-sætninger inden for samme transaktion bevares, og transaktionen forbliver aktiv.
Dette er standardadfærden. Det er med andre ord, hvad der sker under overtrædelser af begrænsninger, når du ikke bruger ON CONFLICT
klausul.
Her er et eksempel på, hvad der sker, når du angiver ABORT
.
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;
Resultat:
Ingen resultater blev returneret, fordi INSERT
operationen blev afbrudt, og bordet er derfor tomt.
Her er, hvad der sker, hvis jeg sætter hver række i sin egen INSERT
erklæring i en transaktion.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0
Fejl
FAIL
option afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl. Men det trækker ikke tilbage tidligere ændringer af SQL-sætningen, der mislykkedes, og det afslutter heller ikke transaktionen.
Her er et eksempel.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99
Her er den i med separat INSERT
opgørelser inden for en transaktion.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0
Ignorer
IGNORE
option springer den ene række over, der indeholder begrænsningsovertrædelsen, og fortsætter med at behandle efterfølgende rækker af SQL-sætningen, som om intet gik galt. Andre rækker før og efter rækken, der indeholdt begrænsningsovertrædelsen, indsættes eller opdateres normalt. Ingen fejl returneres for unikhed, NOT NULL
og UNIQUE
begrænsningsfejl, når denne mulighed bruges. Denne mulighed fungerer dog som ABORT
for fejl med fremmednøgler.
De første eksempler på denne side bruger IGNORE
, men her er den igen.
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;
Resultat:
ProductId ProductName Pris ---------- ------------------ ----------1 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0
Erstat
REPLACE
mulighed fungerer forskelligt afhængigt af overtrædelsen:
- Når en
UNIQUE
ellerPRIMARY KEY
overtrædelse af restriktioner forekommer,,REPLACE
option sletter allerede eksisterende rækker, der forårsager overtrædelsen af begrænsningen, før den aktuelle række indsættes eller opdateres, og kommandoen fortsætter med at udføre normalt. - Hvis en
NOT NULL
overtrædelse af restriktioner, erstatter denNULL
værdi med standardværdien for den kolonne, eller hvis kolonnen ikke har nogen standardværdi, såABORT
algoritme bruges. - Hvis en
CHECK
begrænsning eller fremmednøgle begrænsning opstår, derefterREPLACE
fungerer somABORT
.
Desuden, hvis den sletter rækker for at opfylde en begrænsning, udløses sletning, hvis og kun hvis rekursive triggere er aktiveret.
Her er et eksempel, der bruger REPLACE
mulighed.
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;
Resultat:
ProductId ProductName Pris ---------- ----------- ----------1 Skruenøgle 37,0 2 Søm 1,49 3 Sav 11,34 5 Mejsel 23,0 6 Bandage 120.0
I dette eksempel var konflikten med den primære nøgle (jeg forsøgte at indsætte to rækker med det samme ProductId ). REPLACE
option fik den anden til at erstatte den første.
Tilbage
En anden mulighed er at bruge ROLLBACK
.
Denne indstilling 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.
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', 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;
Her er det fulde output fra min terminal, når jeg kører dette:
sqlite> SLET FRA produkter;sqlite> sqlite> BEGIN TRANSACTION;sqlite> INDSÆT ELLER TILBAGE TIL PRODUKTER VÆRDIER (1, 'Hammer', 9,99); Fejl:NOT NULL begrænsning mislykkedes:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34); sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Skruenøgle', 37.00 INSERTRO e> INSERTRO sqlite); INTO Products VALUES (5, 'Mejsel', 23.00);sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Fejl:kan ikke forpligte - ingen transaktion er aktivsqlite> sqlite> SELECT Produkter;ProductId ProductName Pris ---------- ----------- ----------3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0Så det kom til begrænsningsovertrædelsen og rullede derefter transaktionen tilbage. Derefter blev de efterfølgende 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', 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;
Her er det fulde output fra min terminal, når jeg kører dette:
sqlite> SLET FRA produkter;sqlite> sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (1, 'Hammer', 9,99);sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (2, NULL, 1,49) fejl:mislykkedes:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);sqlite> INSERT INTO ROLLs , 'Mejsel', 23.00);sqlite> INDSÆT ELLER TILBAGE TIL PRODUKTERVÆRDIER (6, 'Bandage', 120.00);sqlite> sqlite> VÆLG * FRA produkter;ProduktId Produktnavn Pris ---------- -- ---------- ----------1 Hammer 9,99 3 Sav 11,34 4 Nøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0I dette tilfælde virkede det som
ABORT
.For at bekræfte, her er den samme erklæring ved hjælp af
ABORT
i stedet forROLLBACK
.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;
Her er det fulde output fra min terminal, når jeg kører dette:
sqlite> DELETE FROM Products;sqlite> sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (1, 'Hammer', 9,99);sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (2, NULL, 1,49);Fejl:IKKE NULL-begrænsning mislykkedes:Products.ProductNamesqlite> INSERT OR AFBORT INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ABORT INTO Products VALUES (4, 'Skruenøgle', 37.00);sqlite> INSERT ELLER AFBRYD I (5 Products VALUES) , 'Mejsel', 23,00);sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (6, 'Bandage', 120,00);sqlite> sqlite> VÆLG * FRA produkter;ProduktId Produktnavn Pris ---------- -- ---------- ----------1 Hammer 9,99 3 Sav 11,34 4 Nøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0