SQLite má ON CONFLICT
klauzule, která vám umožňuje určit, jak zacházet s konflikty omezení. Platí pro UNIQUE
, NOT NULL
, CHECK
a PRIMARY KEY
omezení (ale ne FOREIGN KEY
omezení).
S touto klauzulí můžete použít pět možností:
ABORT
FAIL
IGNORE
REPLACE
ROLLBACK
Tento článek obsahuje příklady a vysvětlení každé z těchto možností.
The ON CONFLICT
klauzule se používá v CREATE TABLE
příkazy, ale lze jej také použít při vkládání nebo aktualizaci dat nahrazením ON CONFLICT
pomocí OR
.
Při vytváření tabulky
Jak již bylo zmíněno, můžete použít ON CONFLICT
při vytváření tabulky nebo při vkládání/aktualizaci dat.
Zde je příklad použití ON CONFLICT
v době vytváření tabulky.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL ON CONFLICT IGNORE,
Price
);
Když použijete ON CONFLICT
klauzuli, použijete ji na konkrétní omezení, které chcete zpracovat. V tomto případě jsem klauzuli přidal do NOT NULL
omezení.
V tomto případě jsem zadal IGNORE
, což znamená, že pokud dojde k porušení omezení, SQLite tento řádek přeskočí a bude pokračovat ve zpracování.
Nyní, když se pokusím vložit NULL
do Název produktu sloupec, který je tento řádek přeskočen.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0
Při vkládání dat
Tuto klauzuli můžete také použít při vkládání a aktualizaci dat. Rozdíl je v tom, že nahradíte ON CONFLICT
pomocí OR
.
Abych to demonstroval, zruším předchozí tabulku a vytvořím ji znovu, ale bez ON CONFLICT
klauzule:
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price
);
Nyní vložím stejná data a použiji OR IGNORE
přeskočit řádek, který porušuje omezení.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0
Dostaneme tedy stejný výsledek jako v předchozím příkladu.
V těchto příkladech jsem použil IGNORE
volba. Toto je pouze jedna z pěti možných možností pro tuto klauzuli.
Níže jsou uvedeny příklady použití každé z pěti možností.
Přerušit
Tato volba zruší aktuální příkaz SQL s chybou SQLITE_CONSTRAINT a zruší všechny změny provedené aktuálním příkazem SQL; ale změny způsobené předchozími příkazy SQL v rámci stejné transakce jsou zachovány a transakce zůstává aktivní.
Toto je výchozí chování. Jinými slovy, toto se stane během porušení omezení, když nepoužijete ON CONFLICT
doložka.
Zde je příklad toho, co se stane, když zadáte 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;
Výsledek:
Nebyly vráceny žádné výsledky, protože INSERT
operace byla přerušena a tabulka je proto prázdná.
Zde je to, co se stane, když vložím každý řádek do vlastního INSERT
výpis v rámci transakce.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0
Neúspěšné
FAIL
volba zruší aktuální příkaz SQL s chybou SQLITE_CONSTRAINT. Neodstraní však předchozí změny příkazu SQL, které selhaly, ani neukončí transakci.
Zde je příklad.
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;
Výsledek:
ProductId ProductName Cena ---------- ----------- ----------1 Hammer 9,99
Zde je to se samostatným INSERT
výpisy v rámci transakce.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0
Ignorovat
IGNORE
volba přeskočí jeden řádek, který obsahuje porušení omezení, a pokračuje ve zpracování následujících řádků příkazu SQL, jako by se nic nestalo. Ostatní řádky před a za řádkem, který obsahoval porušení omezení, jsou vloženy nebo aktualizovány normálně. Pro jedinečnost není vrácena žádná chyba, NOT NULL
a UNIQUE
chyby omezení při použití této možnosti. Tato možnost však funguje jako ABORT
pro chyby omezení cizího klíče.
První příklady na této stránce používají IGNORE
, ale je to tu znovu.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0
Nahradit
REPLACE
Tato možnost funguje odlišně v závislosti na porušení:
- Pokud je
UNIQUE
neboPRIMARY KEY
dojde k porušení omezení,REPLACE
Před vložením nebo aktualizací aktuálního řádku odstraní již existující řádky, které způsobují porušení omezení, a příkaz pokračuje v normálním provádění. - Pokud
NOT NULL
dojde k porušení omezení, nahradíNULL
hodnotu s výchozí hodnotou pro daný sloupec, nebo pokud sloupec nemá žádnou výchozí hodnotu, pakABORT
je použit algoritmus. - Pokud
CHECK
dojde k porušení omezení nebo omezení cizího klíče, potéREPLACE
funguje jakoABORT
.
Pokud také odstraní řádky za účelem splnění omezení, spouštěcí spouštěče se spouštějí pouze tehdy, jsou-li povoleny rekurzivní spouštěče.
Zde je příklad, který používá REPLACE
volba.
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;
Výsledek:
ProductId Název produktu Cena ---------- ----------- ----------1 Klíč 37,0 2 hřebíky 1,49 3 Pila 11,34 5 Sekáč 23,0 6 Obvaz 120,0
V tomto příkladu byl konflikt s primárním klíčem (zkoušel jsem vložit dva řádky se stejným ProductId ). REPLACE
možnost způsobila, že druhá nahradila první.
Vrácení zpět
Další možností je použít ROLLBACK
.
Tato volba zruší aktuální příkaz SQL s chybou SQLITE_CONSTRAINT a vrátí aktuální transakci zpět. Pokud není aktivní žádná transakce (kromě implikované transakce, která je vytvořena při každém příkazu), funguje stejně jako ABORT
algoritmu.
Zde je příklad, který používá více INSERT OR ROLLBACK
výpisy v rámci transakce.
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;
Zde je úplný výstup z mého terminálu, když to spustím:
sqlite> DELETE FROM Products;sqlite> sqlite> ZAČÁTEK TRANSAKCI;sqlite> INSERT NEBO ROLLBACK DO HODNOT produktů (1, 'Hammer', 9,99);sqlite> INSERT OR ROLLBACK DO Products VALUES (2, NULL); 1,49 NULL); Chyba:Omezení NOT NULL selhalo:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);sqERT ROLLBACK> INSERT INTO Products VALUES (5, 'Chisel', 23.00);sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Chyba:nelze potvrdit - žádná transakce není aktivnísqlite> sqlite> SELECT * FROM Products;ProductId ProductName Cena ---------- ----------- ----------3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Bandáž 120,0Takže došlo k porušení omezení a poté transakci odvolala. Poté byly zpracovány následující řádky a poté
COMMIT
bylo nalezeno klíčové slovo. V té době již byla transakce vrácena zpět, a tak jsme dostali další chybu, která nám sdělovala, že žádná transakce nebyla aktivní.Zde je to, co se stane, když jej odstraním z transakce.
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;
Zde je úplný výstup z mého terminálu, když to spustím:
sqlite> DELETE FROM Products;sqlite> sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);Chybové omezení:NOT NULL selhalo: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 OR ROLLBACK INTO , 'Chisel', 23.00);sqlite> VLOŽIT NEBO VRÁTIT DO HODNOT produktů (6, 'Bandage', 120,00);sqlite> sqlite> SELECT * FROM Products;ProductId ProductName Cena ---------- -- --------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0V tomto případě to fungovalo jako
ABORT
.Pro potvrzení je zde stejné prohlášení pomocí
ABORT
místoROLLBACK
.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;
Zde je úplný výstup z mého terminálu, když to spustím:
sqlite> DELETE FROM Products;sqlite> sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);Chyba:NOT NULL omezení selhalo:Products.ProductNamesqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ABORT INTO Products VALUES (4, 'Wrench', 37.00);sqlite> INSERT OR ABORT INTO Products VALUES , 'Chisel', 23.00);sqlite> INSERT NEBO ABORT INTO Products VALUES (6, 'Bandage', 120.00);sqlite> sqlite> SELECT * FROM Products;ProductId ProductName Cena ----------- -- --------- ----------1 Kladivo 9,99 3 Pila 11,34 4 Klíč 37,0 5 Sekáč 23,0 6 Obvaz 120,0