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í:
ABORTFAILIGNOREREPLACEROLLBACK
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
UNIQUEneboPRIMARY KEYdojde k porušení omezení,REPLACEPř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 NULLdojde k porušení omezení, nahradíNULLhodnotu s výchozí hodnotou pro daný sloupec, nebo pokud sloupec nemá žádnou výchozí hodnotu, pakABORTje použit algoritmus. - Pokud
CHECKdojde k porušení omezení nebo omezení cizího klíče, potéREPLACEfunguje 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é
COMMITbylo 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í
ABORTmí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