En af SQLites ikke-standardudvidelser til SQL er ON CONFLICT
klausul.
Denne klausul giver dig mulighed for at bestemme, hvad der skal ske, når visse konflikter opstår på grund af en overtrædelse af begrænsninger.
En af de ting, du kan bruge denne klausul til, er at erstatte NULL
værdier med en kolonnes standardværdi, når du indsætter eller opdaterer data i en tabel.
Som standard, hvis du prøver at indsætte NULL
ind i en kolonne med en NOT NULL
begrænsning, vil det mislykkes.
Og hvis du prøver at indsætte NULL
ind i en kolonne uden en NOT NULL
begrænsning, derefter NULL
vil blive tildelt den kolonne, selvom der er en DEFAULT
klausul.
Du kan dog bruge ON CONFLICT
klausul for at sætte den til standardværdien i stedet for NULL
.
Eksempel
Den følgende kode viser, hvad jeg mener.
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price NOT NULL ON CONFLICT REPLACE DEFAULT 0.00
);
INSERT INTO Products (ProductId, ProductName, Price) VALUES
(1, 'Widget Holder', NULL);
SELECT * FROM Products;
I dette eksempel bruger jeg ON CONFLICT REPLACE
for at indstille NULL
værdier til standardværdien i stedet for NULL
.
Her er resultatet fra SELECT
sætning på sidste linje:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Vi kan se, at Prisen kolonne har standardværdien 0,0, selvom jeg har forsøgt at indsætte NULL
.
Lad os se, hvad der sker, hvis jeg fjerner NOT NULL
begrænsning.
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price DEFAULT 0.00
);
INSERT INTO Products (ProductId, ProductName, Price) VALUES
(1, 'Widget Holder', NULL);
SELECT * FROM Products;
Resultat:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder
Nu indeholder kolonnen NULL
.
Indsættelse af NULL implicit
Det er vigtigt at bemærke, at denne artikel hovedsageligt handler om at indsætte NULL
eksplicit .
Hvis du prøver at indsætte NULL
implicit , så vil det foregående eksempel give et andet resultat.
Hvad jeg mener er, hvis du ikke inkluderer kolonnen i INSERT
sætning, DEFAULT
begrænsning vil blive brugt automatisk. Det er hvad DEFAULT
begrænsninger er for – at give en værdi, når du ikke eksplicit angiver en.
Her er, hvad der sker, når jeg gør det.
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price DEFAULT 0.00
);
INSERT INTO Products (ProductId, ProductName) VALUES
(1, 'Widget Holder');
SELECT * FROM Products;
Resultat:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Så alt, hvad jeg gjorde, var at fjerne prisen kolonne fra INSERT
erklæring.
ON CONFLICT for INSERT-erklæringen
Det første eksempel bruger ON CONFLICT
på CREATE TABLE
erklæring.
Men hvad nu hvis tabellen ikke blev oprettet med ON CONFLICT
klausul?
Heldigvis er der også en måde at bruge det på INSERT
udmelding.
Syntaksen er lidt anderledes. Når det bruges på INSERT
sætning, du skal erstatte ON CONFLICT
med OR
.
Lad os ændre koden for at bruge denne metode.
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price NOT NULL DEFAULT 0.00
);
INSERT OR REPLACE INTO Products (ProductId, ProductName, Price) VALUES
(1, 'Widget Holder', NULL);
SELECT * FROM Products;
Resultat:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Så jeg erstattede INSERT INTO
med INSERT OR REPLACE INTO
.
Her er, hvad resultatet ville være, hvis jeg ikke havde lagt den klausul ind.
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price NOT NULL DEFAULT 0.00
);
INSERT INTO Products (ProductId, ProductName, Price) VALUES
(1, 'Widget Holder', NULL);
SELECT * FROM Products;
Resultat:
Error: NOT NULL constraint failed: Products.Price
Ingen DEFAULT-begrænsning?
I tilfælde af at du bruger ON CONFLICT
klausul på en kolonne uden en DEFAULT
begrænsning, SQL-sætningen afbrydes med en SQLITE_CONSTRAINT-fejl, alle ændringer foretaget af den aktuelle SQL-sætning sikkerhedskopieres; men ændringer forårsaget af tidligere SQL-sætninger inden for samme transaktion bevares, og transaktionen forbliver aktiv.