SQLite
 sql >> база данни >  >> RDS >> SQLite

Справяне с конфликти на първичен ключ при вмъкване на данни в SQLite

SQLite има нестандартна клауза за разширение на SQL, наречена ON CONFLICT което ни позволява да уточним как да се справяме с конфликтите на ограничения.

По-специално, клаузата се отнася за UNIQUE , NOT NULL , CHECK и PRIMARY KEY ограничения.

Тази статия предоставя примери за това как тази клауза може да се използва, за да се определи как да се обработват конфликти на ограничения на първичния ключ.

Под „конфликти на ограничения на първичния ключ“ имам предвид, когато се опитвате да вмъкнете дублирана стойност в колона за първичен ключ. По подразбиране, когато се опитате да направите това, операцията ще бъде прекъсната и SQLite ще върне грешка.

Но можете да използвате ON CONFLICT клауза за промяна на начина, по който SQLite се справя с тези ситуации.

Една от опциите е да използвате тази клауза в CREATE TABLE изявление при създаване на таблицата. Това ще определи как всички INSERT операции се лекуват.

Друга възможност е да използвате клаузата в INSERT изявление всеки път, когато се опитате да вмъкнете данни в таблицата. Това ви позволява да се възползвате от клаузата, дори когато таблицата не е създадена с нея. Когато използвате тази опция, синтаксисът е различен; използвате OR вместо ON CONFLICT .

Примерите на тази страница използват втората опция – създавам таблицата без ON CONFLICT клауза и вместо това указвам OR на INSERT изявление.

Примерна таблица

Нека създадем проста таблица и да добавим един ред.

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

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

SELECT * FROM Products;

Резултат:

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

В момента имаме един ред с ProductId от 1 .

Сега можем да преминем през различните сценарии на вмъкване на данни в тази таблица, която нарушава ограничението на първичния ключ.

Пример 1 – Прекратяване (поведение по подразбиране)

Както споменахме, поведението по подразбиране за SQLite е да прекъсне INSERT операция и върне грешка.

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

Резултат:

Error: UNIQUE constraint failed: Products.ProductId

Беше върната грешка и нищо не беше въведено.

Това е еквивалентно на използването на OR ABORT опция.

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

Резултат:

Error: UNIQUE constraint failed: Products.ProductId

Можем да проверим дали нищо не е вмъкнато, като изпълним SELECT изявление срещу масата.

SELECT * FROM Products;

Резултат:

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

Можем да видим, че таблицата съдържа само оригиналния ред.

Пример 2 – Игнориране

Една алтернатива е SQLite да игнорира нарушителния ред. С други думи, той ще пропусне реда и ще продължи да обработва следващите редове.

За да направите това във вашия INSERT израз, използвайте OR IGNORE .

Ефектът от това е, че INSERT операцията е успешна, но без редове, които нарушават ограничението на първичния ключ.

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;

Резултат:

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

В този случай се опитах да вмъкна два нови реда с идентификатор, който вече съществуваше в таблицата, така че и двата реда бяха пропуснати.

Пример 3 – Замяна

Друга опция, която имате, е да замените оригиналния ред с новия.

С други думи, ще презапишете съществуващите данни с новите си данни.

За да направите това, използвайте 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;

Резултат:

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

В този случай повечето редове бяха еднакви, така че съдържат едни и същи данни след INSERT операция. Въпреки това можем да видим, че първият ред е актуализиран, за да използва стойностите в моя INSERT изявление.

Можем също да видим, че е използвал втория набор от стойности (виждайки, че двама споделят един и същ ProductId ).

Така че ефектът е нещо като UPDATE изявление и INSERT комбинирано изявление.

Пример 4 – връщане назад

Друга възможност е да използвате ROLLBACK опция.

Това прекратява текущия SQL оператор с грешка SQLITE_CONSTRAINT и връща текущата транзакция. Ако нито една транзакция не е активна (освен подразбиращата се транзакция, която се създава при всяка команда), тя работи по същия начин като ABORT алгоритъм.

Струва си да имате предвид как работи тази опция. Ето пример, който използва множество INSERT OR ROLLBACK извлечения в рамките на транзакция.

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;

Ето пълния изход от моя терминал, когато стартирам това:

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> 

По същество това, което се случи тук, е, че е стигнало до нарушението на ограничението, след което е върнало транзакцията. След това бяха обработени следващите два реда и след това COMMIT беше открита ключова дума. Дотогава транзакцията вече беше отменена и така получихме друга грешка, която ни казва, че няма активна транзакция.

Ето какво се случва, ако го премахна от транзакцията.

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;

Ето пълния изход от моя терминал, когато стартирам това:

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>

В този случай работеше като ABORT .

За да демонстрирате това, ето същото изявление с помощта на ABORT вместо 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;

Ето пълния изход от моя терминал, когато стартирам това:

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> 

Опцията за отказ

FAIL опция прекратява текущия SQL израз с грешка SQLITE_CONSTRAINT. Но тази опция не отменя предишни промени на SQL израза, който не е успял, нито прекратява транзакцията.

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;

Резултат:

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

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. импортирайте вече създадена sqlite база данни (xamarin)

  2. SQLite - Не можа да се отвори файл на базата данни

  3. Изпълнение на Total-Order By Date в SQLite

  4. Могат ли записи в базата данни, добавени от елементи, да бъдат изтрити с бутон?

  5. SQLite AVG