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.