Едно от нестандартните разширения на SQLite към SQL е ON CONFLICT
клауза.
Тази клауза ви позволява да определите какво трябва да се случи, когато възникнат определени конфликти поради нарушение на ограничението.
Едно от нещата, за които можете да използвате тази клауза, е да замените NULL
стойности със стойността по подразбиране на колона при вмъкване или актуализиране на данни в таблица.
По подразбиране, ако се опитате изрично да вмъкнете NULL
в колона с NOT NULL
ограничение, то ще се провали.
И ако се опитате изрично да вмъкнете NULL
в колона без a NOT NULL
ограничение, след това NULL
ще бъде присвоен на тази колона, дори ако има DEFAULT
клауза.
Можете обаче да използвате ON CONFLICT
клауза, за да го зададете на стойността по подразбиране вместо NULL
.
Пример
Следният код показва какво имам предвид.
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;
В този пример използвам ON CONFLICT REPLACE
за да зададете NULL
стойности към стойността по подразбиране вместо NULL
.
Ето резултата от SELECT
изявление на последния ред:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Виждаме, че Цената колоната има стойност по подразбиране 0.0, въпреки че се опитах изрично да вмъкна NULL
.
Нека видим какво ще се случи, ако премахна NOT NULL
ограничение.
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;
Резултат:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder
Сега колоната съдържа NULL
.
Неявно вмъкване на NULL
Важно е да се отбележи, че тази статия се занимава основно с вмъкване на NULL
изрично .
Ако се опитате да вмъкнете NULL
имплицитно , тогава предишният пример ще даде различен резултат.
Имам предвид, че ако не включите колоната в INSERT
оператор, DEFAULT
ограничението ще се използва автоматично. Това е, което DEFAULT
ограниченията са за – за предоставяне на стойност, когато не сте предоставили изрично такава.
Ето какво се случва, когато го направя.
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;
Резултат:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Така че всичко, което направих, беше да премахна Цена колона от INSERT
изявление.
В КОНФЛИКТ за изявлението INSERT
Първият пример използва ON CONFLICT
на CREATE TABLE
изявление.
Но какво ще стане, ако таблицата не е създадена с ON CONFLICT
клауза?
За щастие има и начин да го използвате в INSERT
изявление.
Синтаксисът е малко по-различен. Когато се използва в INSERT
изявление, което трябва да замените ON CONFLICT
с OR
.
Нека модифицираме кода, за да използваме този метод.
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;
Резултат:
ProductId ProductName Price ---------- ------------- ---------- 1 Widget Holder 0.0
Затова замених INSERT INTO
с INSERT OR REPLACE INTO
.
Ето какъв би бил резултатът, ако не поставих тази клауза.
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;
Резултат:
Error: NOT NULL constraint failed: Products.Price
Няма ограничение ПО ПОДРАЗБИРАНЕ?
В случай, че използвате ON CONFLICT
клауза в колона без DEFAULT
ограничение, SQL операторът се прекратява с грешка SQLITE_CONSTRAINT, всички промени, направени от текущия SQL оператор, се отменят; но промените, причинени от предишни SQL оператори в рамките на същата транзакция, се запазват и транзакцията остава активна.