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

Как работи ON CONFLICT в SQLite

SQLite има ON CONFLICT клауза, която ви позволява да укажете как да се справите с конфликти на ограничения. Прилага се за UNIQUE , NOT NULL , CHECK и PRIMARY KEY ограничения (но не и FOREIGN KEY ограничения).

Има пет възможни опции, които можете да използвате с тази клауза:

  • ABORT
  • FAIL
  • IGNORE
  • REPLACE
  • ROLLBACK

Тази статия предоставя примери и обяснение на всяка от тези опции.

ON CONFLICT клаузата се използва в CREATE TABLE изрази, но може да се използва и при вмъкване или актуализиране на данни чрез замяна на ON CONFLICT с OR .

При създаване на таблицата

Както споменахме, можете да използвате ON CONFLICT когато създавате таблицата или когато вмъквате/актуализирате данни.

Ето пример за използване на ON CONFLICT в момента на създаване на таблицата.

CREATE TABLE Products( 
    ProductId INTEGER PRIMARY KEY, 
    ProductName NOT NULL ON CONFLICT IGNORE, 
    Price
); 

Когато използвате ON CONFLICT клауза, я прилагате към специфичното ограничение, което искате да обработвате. В този случай добавих клаузата към NOT NULL ограничение.

В този случай посочих IGNORE , което означава, че ако има нарушение на ограничението, SQLite ще пропусне този ред и след това ще продължи обработката.

Сега, ако се опитам да вмъкна NULL в ProductName колона този ред е пропуснат.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120.0 

При вмъкване на данни

Можете също да използвате тази клауза, когато вмъквате и актуализирате данни. Разликата е, че замествате ON CONFLICT с OR .

За да демонстрирам, ще пусна предишната таблица и ще я създам отново, но без ON CONFLICT клауза:

DROP TABLE IF EXISTS Products;

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

Сега ще вмъкна същите данни и ще използвам OR IGNORE за да пропуснете реда, който нарушава ограничението.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120.0 

Така получаваме същия резултат като в предишния пример.

В тези примери използвах IGNORE опция. Това е само една от петте възможни опции за тази клауза.

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

Прекратяване

Тази опция прекратява текущия SQL оператор с грешка SQLITE_CONSTRAINT и отменя всички промени, направени от текущия SQL оператор; но промените, причинени от предишни SQL оператори в рамките на същата транзакция, се запазват и транзакцията остава активна.

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

Ето пример за това какво се случва, когато посочите 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; 

Резултат:

 

Не бяха върнати резултати, защото INSERT операцията е прекратена и таблицата е празна.

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

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120.0 

Неуспешно

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

Ето един пример.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Hammer 9,99 

Ето го с отделен INSERT извлечения в рамките на транзакция.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120.0 

Игнориране

IGNORE опцията пропуска единия ред, който съдържа нарушението на ограничението и продължава да обработва следващите редове от SQL израза, сякаш нищо не се е объркало. Други редове преди и след реда, съдържащ нарушението на ограничението, се вмъкват или актуализират нормално. Не се връща грешка за уникалност, NOT NULL и UNIQUE грешки при ограничаване, когато се използва тази опция. Тази опция обаче работи като ABORT за грешки при ограничаване на външния ключ.

Първите примери на тази страница използват IGNORE , но ето го отново.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120.0 

Замяна

REPLACE опцията работи различно в зависимост от нарушението:

  • Когато е UNIQUE или PRIMARY KEY възниква нарушение на ограничението, REPLACE опцията изтрива вече съществуващи редове, които причиняват нарушение на ограничението, преди да вмъкне или актуализира текущия ред и командата продължава да се изпълнява нормално.
  • Ако NOT NULL възниква нарушение на ограничението, то заменя NULL стойност със стойността по подразбиране за тази колона или ако колоната няма стойност по подразбиране, тогава ABORT се използва алгоритъм.
  • Ако CHECK възникне нарушение на ограничение или ограничение на външния ключ, след което REPLACE работи като ABORT .

Освен това, ако изтрие редове, за да удовлетвори ограничение, тригерите за изтриване се задействат, ако и само ако рекурсивните задействания са разрешени.

Ето пример, който използва REPLACE опция.

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; 

Резултат:

ProductId ProductName Цена ---------- ----------- ----------1 Гаечен ключ 37,0 2 Пирон 1,49 3 Трион 11,34 5 Длето 23,0 6 Бинт 120.0 

В този пример конфликтът беше с първичния ключ (опитах се да вмъкна два реда със същия ProductId ). REPLACE опция накара втория да замени първия.

Отмяна

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

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

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

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; 

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

sqlite> ИЗТРИВАНЕ ОТ продукти;sqlite> sqlite> ЗАПОЧНЕТЕ ТРАНЗАКЦИЯ;sqlite> ВМЪКВАНЕ ИЛИ ВРЪЩАНЕ В ПРОДУКТИ СТОЙНОСТИ (1, 'Hammer', 9.99);sqlite> ВМЪКВАНЕ ИЛИ връщане в стойности на продукти (2.49); Грешка:Ограничението NOT NULL неуспешно:Products.ProductNamesqlite> INSERT OR ROLLBACK IN TO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00 ROLLBACK> IN); INTO СТОЙНОСТИ (5, 'Chisel', 23.00);sqlite> ВМЕСТЕ ИЛИ ВРЪЩАНЕ В ПРОДУКТИ СТОЙНОСТИ (6, 'Bandage', 120.00);sqlite> COMMIT; Грешка:не може да се извърши - няма активна транзакция sqlite> * FROM> SELECT Продукти;ProductId ProductName Цена ---------- ----------- ----------3 Трион 11,34 4 Гаечен ключ 37,0 5 Длетото 23,0 6 Бинт 120,0  

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

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

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; 

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

sqlite> ИЗТРИВАНЕ ОТ продукти;sqlite> sqlite> ВМЪКВАНЕ ИЛИ ВРЪЩАНЕ В ПРОДУКТИ СТОЙНОСТИ (1, 'Hammer', 9.99);sqlite> ВМЕСВАНЕ ИЛИ ВРЪЩАНЕ В ПРОДУКТИ СТОЙНОСТИ (2, NULL, 1.49); Грешка constra:NUINT неуспешно:Products.ProductNamesqlite> INSERT OR ROLLBACK IN TO Products STOS (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK IN TO Products STOS (4, 'Wrench', 37.00);sqlite> INSERT STO (ВМЪКВАНЕ НА СТОЙНОСТ ИЛИ 5 Product ROLLB) , 'Chisel', 23.00);sqlite> ВМЕСТЕ ИЛИ ВРЪЩАНЕ В ПРОДУКТИ СТОЙНОСТИ (6, 'Bandage', 120.00);sqlite> sqlite> ИЗБЕРЕТЕ * ОТ Продукти;ProductId ProductName Цена ---------- -- --------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120,0 

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

За да потвърдите, ето същото изявление с помощта на ABORT вместо ROLLBACK .

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; 

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

sqlite> ИЗТРИВАНЕ ОТ продукти;sqlite> sqlite> ВМЪКВАНЕ ИЛИ ПРЕКРАТЯВАНЕ В ПРОДУКТИ СТОЙНОСТИ (1, 'Hammer', 9.99);sqlite> ВМЕСВАНЕ ИЛИ ПРЕКРАТЯВАНЕ В ПРОДУКТИ СТОЙНОСТИ (2, NULL, 1.49); Грешка constraint NULL неуспешно: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 ABORS VALUE IN (5 , 'Chisel', 23.00);sqlite> ВМЕСТЕ ИЛИ ПРЕКРАНЕТЕ В ПРОДУКТИ СТОЙНОСТИ (6, 'Bandage', 120.00);sqlite> sqlite> ИЗБЕРЕТЕ * ОТ Продукти;ProductId ProductName Цена ---------- -- --------- ----------1 Чук 9,99 3 Трион 11,34 4 Гаечен ключ 37,0 5 Длето 23,0 6 Бинт 120,0 


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. GreenDao freemaker.jar липсва

  2. Производителност на Android Sqlite

  3. Close никога не е бил извикан изрично в базата данни

  4. Задайте стойност по подразбиране на целочислена колона SQLite

  5. Относно SQLite