Jednym z niestandardowych rozszerzeń SQLite dla SQL jest ON CONFLICT
klauzula.
Ta klauzula pozwala określić, co powinno się stać, gdy wystąpią określone konflikty z powodu naruszenia ograniczenia.
Jedną z rzeczy, do których możesz użyć tej klauzuli, jest zastąpienie NULL
wartości z domyślną wartością kolumny podczas wstawiania lub aktualizowania danych w tabeli.
Domyślnie, jeśli spróbujesz jawnie wstawić NULL
do kolumny z NOT NULL
ograniczenia, to się nie powiedzie.
A jeśli spróbujesz jawnie wstawić NULL
do kolumny bez a NOT NULL
ograniczenie, a następnie NULL
zostanie przypisany do tej kolumny, nawet jeśli istnieje DEFAULT
klauzula.
Możesz jednak użyć ON CONFLICT
klauzulę, aby ustawić ją na wartość domyślną zamiast NULL
.
Przykład
Poniższy kod pokazuje, o co mi chodzi.
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;
W tym przykładzie używam ON CONFLICT REPLACE
aby ustawić NULL
wartości do wartości domyślnej zamiast NULL
.
Oto wynik z SELECT
oświadczenie w ostatniej linii:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Widzimy, że Cena kolumna ma domyślną wartość 0,0, mimo że próbowałem jawnie wstawić NULL
.
Zobaczmy, co się stanie, jeśli usunę NOT NULL
ograniczenie.
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;
Wynik:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder
Teraz kolumna zawiera NULL
.
Niejawne wstawianie wartości NULL
Należy zauważyć, że ten artykuł dotyczy głównie wstawiania NULL
wyraźnie .
Jeśli spróbujesz wstawić NULL
domyślnie , poprzedni przykład da inny wynik.
Mam na myśli to, że jeśli nie uwzględnisz kolumny w INSERT
oświadczenie, DEFAULT
ograniczenie zostanie użyte automatycznie. To właśnie DEFAULT
ograniczenia są dla – aby podać wartość, gdy jej wyraźnie nie podasz.
Oto, co się dzieje, gdy to robię.
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;
Wynik:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Więc jedyne, co zrobiłem, to usunąłem cenę kolumna z INSERT
oświadczenie.
ON CONFLICT dla instrukcji INSERT
Pierwszy przykład używa ON CONFLICT
na CREATE TABLE
oświadczenie.
Ale co, jeśli tabela nie została utworzona za pomocą ON CONFLICT
klauzula?
Na szczęście istnieje również sposób na użycie go na INSERT
oświadczenie.
Składnia jest nieco inna. W przypadku użycia na INSERT
oświadczenie, które musisz zastąpić ON CONFLICT
z OR
.
Zmodyfikujmy kod, aby korzystać z tej metody.
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;
Wynik:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Więc zastąpiłem INSERT INTO
z INSERT OR REPLACE INTO
.
Oto, jaki byłby wynik, gdybym nie umieścił tej klauzuli.
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;
Wynik:
Error: NOT NULL constraint failed: Products.Price
Brak ograniczeń DOMYŚLNYCH?
W przypadku użycia opcji ON CONFLICT
klauzula na kolumnie bez DEFAULT
ograniczenie, instrukcja SQL jest przerywana z błędem SQLITE_CONSTRAINT wszelkie zmiany wprowadzone przez bieżącą instrukcję SQL są wycofywane; ale zmiany spowodowane wcześniejszymi instrukcjami SQL w ramach tej samej transakcji są zachowywane, a transakcja pozostaje aktywna.