sql >> Databáze >  >> RDS >> SQLite

Řešení konfliktů primárního klíče při vkládání dat do SQLite

SQLite má nestandardní klauzuli rozšíření SQL s názvem ON CONFLICT což nám umožňuje specifikovat, jak se vypořádat s konflikty omezení.

Tato klauzule platí zejména pro UNIQUE , NOT NULL , CHECK a PRIMARY KEY omezení.

Tento článek poskytuje příklady toho, jak lze tuto klauzuli použít k určení, jak zpracovat konflikty omezení primárního klíče.

„Konflikty omezení primárního klíče“ mám na mysli, když se pokusíte vložit duplicitní hodnotu do sloupce primárního klíče. Ve výchozím nastavení, když se o to pokusíte, bude operace přerušena a SQLite vrátí chybu.

Ale můžete použít ON CONFLICT klauzule ke změně způsobu, jakým SQLite řeší tyto situace.

Jednou z možností je použít tuto klauzuli v CREATE TABLE při vytváření tabulky. Tím určíte, jak budou všechny INSERT operace jsou ošetřeny.

Další možností je použít klauzuli na INSERT kdykoli se pokusíte vložit data do tabulky. To vám umožní využít klauzuli, i když s ní nebyla vytvořena tabulka. Při použití této možnosti se syntaxe liší; používáte OR místo ON CONFLICT .

Příklady na této stránce využívají druhou možnost – vytvořím tabulku bez ON CONFLICT klauzuli a místo toho uvedu OR na INSERT prohlášení.

Ukázková tabulka

Vytvoříme jednoduchou tabulku a přidáme jeden řádek.

CREATE TABLE Products( 
    ProductId INTEGER PRIMARY KEY, 
    ProductName, 
    Price
);

INSERT INTO Products VALUES (1, 'Hammer', 8.00);

SELECT * FROM Products;

Výsledek:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       

Aktuálně máme jeden řádek s ProductId z 1 .

Nyní můžeme projít různé scénáře vkládání dat do této tabulky, která porušuje omezení primárního klíče.

Příklad 1 – Přerušit (výchozí chování)

Jak již bylo zmíněno, výchozí chování pro SQLite je zrušit INSERT operaci a vrátí chybu.

INSERT INTO Products VALUES (1, 'Wrench', 12.50);

Výsledek:

Error: UNIQUE constraint failed: Products.ProductId

Byla vrácena chyba a nic nebylo vloženo.

Toto je ekvivalent použití OR ABORT možnost.

INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 12.50);

Výsledek:

Error: UNIQUE constraint failed: Products.ProductId

Že nebylo nic vloženo, můžeme ověřit spuštěním SELECT prohlášení proti tabulce.

SELECT * FROM Products;

Výsledek:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       

Vidíme, že tabulka obsahuje pouze původní řádek.

Příklad 2 – Ignorovat

Jednou z alternativ je nechat SQLite ignorovat problematický řádek. Jinými slovy, přeskočí řádek a bude pokračovat ve zpracování následujících řádků.

Chcete-li to provést v rámci INSERT použijte příkaz OR IGNORE .

Výsledkem je, že INSERT operace je úspěšná, ale bez řádků, které porušují omezení primárního klíče.

INSERT OR IGNORE INTO Products VALUES 
  (1, 'Hammer', 12.00),
  (2, 'Nails', 2.50),
  (3, 'Saw', 10.50),
  (1, 'Wrench', 22.50),
  (5, 'Chisel', 23.00),
  (6, 'Bandage', 120.00);

SELECT * FROM Products;

Výsledek:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     

V tomto případě jsem se pokusil vložit dva nové řádky s ID, které již v tabulce existovalo, takže oba tyto řádky byly přeskočeny.

Příklad 3 – Nahradit

Další možností je nahradit původní řádek novým řádkem.

Jinými slovy, přepíšete stávající data svými novými daty.

Chcete-li to provést, použijte OR REPLACE .

INSERT OR REPLACE INTO Products VALUES 
  (1, 'Hammer', 12.00),
  (2, 'Nails', 2.50),
  (3, 'Saw', 10.50),
  (1, 'Wrench', 22.50),
  (5, 'Chisel', 23.00),
  (6, 'Bandage', 120.00);

SELECT * FROM Products;

Výsledek:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Wrench       22.5      
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     

V tomto případě byla většina řádků stejná, takže za INSERT obsahují stejná data úkon. Vidíme však, že první řádek byl aktualizován tak, aby používal hodnoty v mém INSERT prohlášení.

Můžeme také vidět, že používá druhou sadu hodnot (přičemž dvě sdílejí stejné ProductId ).

Takže efekt je něco jako UPDATE a INSERT prohlášení kombinované.

Příklad 4 – Vrácení zpět

Další možností je použít ROLLBACK možnost.

To 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.

Vyplatí se mít na paměti, jak tato možnost funguje. 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', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
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> BEGIN TRANSACTION;
sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 8.00);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
Error: UNIQUE constraint failed: Products.ProductId
sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
sqlite> COMMIT;
Error: cannot commit - no transaction is active
sqlite>   
sqlite> SELECT * FROM Products;
ProductId   ProductName  Price     
----------  -----------  ----------
5           Chisel       23.0      
6           Bandage      120.0     
sqlite> 

V podstatě to, co se stalo, je to, že se to dostalo až k porušení omezení a pak transakci odvolala. Poté byly zpracovány další dva řá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', 8.00);
INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
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', 8.00);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, 'Nails', 2.50);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 10.50);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Wrench', 22.50);
Error: UNIQUE constraint failed: Products.ProductId
sqlite> INSERT OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);
sqlite>   
sqlite> SELECT * FROM Products;
ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     
sqlite>

V tomto případě to fungovalo jako ABORT .

Abychom to demonstrovali, zde je stejné prohlášení pomocí ABORT místo ROLLBACK .

DELETE FROM Products;

INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 8.00);
INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
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', 8.00);
sqlite> INSERT OR ABORT INTO Products VALUES (2, 'Nails', 2.50);
sqlite> INSERT OR ABORT INTO Products VALUES (3, 'Saw', 10.50);
sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Wrench', 22.50);
Error: UNIQUE constraint failed: Products.ProductId
sqlite> INSERT OR ABORT INTO Products VALUES (5, 'Chisel', 23.00);
sqlite> INSERT OR ABORT INTO Products VALUES (6, 'Bandage', 120.00);
sqlite>   
sqlite> SELECT * FROM Products;
ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      
5           Chisel       23.0      
6           Bandage      120.0     
sqlite> 

Možnost selhání

FAIL volba zruší aktuální příkaz SQL s chybou SQLITE_CONSTRAINT. Tato možnost však neodvolá předchozí změny příkazu SQL, které selhaly, ani neukončí transakci.

DELETE FROM Products;

INSERT OR FAIL INTO Products VALUES 
  (1, 'Hammer', 8.00),
  (2, 'Nails', 2.50),
  (3, 'Saw', 10.50),
  (1, 'Wrench', 22.50),
  (5, 'Chisel', 23.00),
  (6, 'Bandage', 120.00);

SELECT * FROM Products;

Výsledek:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       8.0       
2           Nails        2.5       
3           Saw          10.5      

  1. Co je SQL?

  2. Převeďte Unixové časové razítko na hodnotu data v Oracle

  3. JSON v SQL Server

  4. PostgreSQL zrušení oprávnění z tabulek pg_catalog