SQLite
 sql >> Baza danych >  >> RDS >> SQLite

Jak ON CONFLICT działa w SQLite

SQLite ma ON CONFLICT klauzula, która pozwala określić sposób obsługi konfliktów ograniczeń. Dotyczy UNIQUE , NOT NULL , CHECK i PRIMARY KEY ograniczenia (ale nie FOREIGN KEY ograniczenia).

Istnieje pięć możliwych opcji, których można użyć z tą klauzulą:

  • ABORT
  • FAIL
  • IGNORE
  • REPLACE
  • ROLLBACK

Ten artykuł zawiera przykłady i wyjaśnienie każdej z tych opcji.

ON CONFLICT klauzula jest używana w CREATE TABLE oświadczenia, ale można go również użyć podczas wstawiania lub aktualizowania danych, zastępując ON CONFLICT z OR .

Podczas tworzenia tabeli

Jak wspomniano, możesz użyć ON CONFLICT podczas tworzenia tabeli lub podczas wstawiania/aktualizowania danych.

Oto przykład użycia ON CONFLICT w momencie tworzenia tabeli.

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

Gdy używasz ON CONFLICT klauzulę, zastosujesz ją do konkretnego ograniczenia, które chcesz obsłużyć. W tym przypadku dodałem klauzulę do NOT NULL ograniczenie.

W tym przypadku określiłem IGNORE , co oznacza, że ​​jeśli wystąpi naruszenie ograniczenia, SQLite pominie ten wiersz, a następnie będzie kontynuować przetwarzanie.

Teraz, jeśli spróbuję wstawić NULL do ProductName kolumna, której wiersz jest pomijany.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Podczas wstawiania danych

Możesz również użyć tej klauzuli podczas wstawiania i aktualizowania danych. Różnica polega na tym, że zastępujesz ON CONFLICT z OR .

Aby to zademonstrować, usunę poprzednią tabelę i utworzę ją ponownie, ale bez ON CONFLICT klauzula:

DROP TABLE IF EXISTS Products;

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

Teraz wstawię te same dane i użyję OR IGNORE aby pominąć wiersz, który narusza ograniczenie.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Otrzymujemy więc ten sam wynik, co w poprzednim przykładzie.

W tych przykładach użyłem IGNORE opcja. To tylko jedna z pięciu możliwych opcji dla tej klauzuli.

Poniżej znajdują się przykłady użycia każdej z pięciu opcji.

Przerwij

Ta opcja przerywa bieżącą instrukcję SQL z błędem SQLITE_CONSTRAINT i wycofuje wszelkie zmiany wprowadzone przez bieżącą instrukcję SQL; ale zmiany spowodowane wcześniejszymi instrukcjami SQL w ramach tej samej transakcji są zachowywane, a transakcja pozostaje aktywna.

To jest zachowanie domyślne. Innymi słowy, dzieje się tak podczas naruszeń ograniczeń, gdy nie używasz ON CONFLICT klauzula.

Oto przykład tego, co się dzieje, gdy podasz 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;

Wynik:

 

Nie zwrócono żadnych wyników, ponieważ INSERT operacja została przerwana i dlatego tabela jest pusta.

Oto, co się stanie, jeśli umieszczę każdy wiersz we własnym INSERT wyciąg w ramach transakcji.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Niepowodzenie

FAIL opcja przerywa bieżącą instrukcję SQL z błędem SQLITE_CONSTRAINT. Ale nie wycofuje wcześniejszych zmian w instrukcji SQL, która się nie powiodła, ani nie kończy transakcji.

Oto przykład.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      

Tutaj jest w oddzielnym INSERT wyciągi w ramach transakcji.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Ignoruj

IGNORE opcja pomija jeden wiersz, który zawiera naruszenie ograniczenia i kontynuuje przetwarzanie kolejnych wierszy instrukcji SQL, tak jakby nic nie poszło nie tak. Inne wiersze przed i za wierszem zawierającym naruszenie ograniczenia są wstawiane lub aktualizowane normalnie. Żaden błąd nie jest zwracany dla wyjątkowości, NOT NULL i UNIQUE błędy wiązań, gdy ta opcja jest używana. Jednak ta opcja działa jak ABORT dla błędów ograniczeń klucza obcego.

Pierwsze przykłady na tej stronie używają IGNORE , ale znowu jest.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Hammer       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Zamień

REPLACE opcja działa różnie w zależności od naruszenia:

  • Gdy UNIQUE lub PRIMARY KEY występuje naruszenie ograniczenia, REPLACE opcja usuwa wcześniej istniejące wiersze, które powodują naruszenie ograniczenia przed wstawieniem lub aktualizacją bieżącego wiersza, a polecenie kontynuuje normalne wykonywanie.
  • Jeśli NOT NULL występuje naruszenie ograniczenia, zastępuje NULL wartość z wartością domyślną dla tej kolumny lub jeśli kolumna nie ma wartości domyślnej, to ABORT używany jest algorytm.
  • Jeśli CHECK występuje naruszenie ograniczenia lub klucza obcego, a następnie REPLACE działa jak ABORT .

Ponadto, jeśli usuwa wiersze w celu spełnienia ograniczenia, wyzwalacze usuwania są uruchamiane wtedy i tylko wtedy, gdy włączone są wyzwalacze rekurencyjne.

Oto przykład, w którym użyto REPLACE opcja.

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;

Wynik:

ProductId   ProductName  Price     
----------  -----------  ----------
1           Wrench       37.0      
2           Nails        1.49      
3           Saw          11.34     
5           Chisel       23.0      
6           Bandage      120.0     

W tym przykładzie konflikt dotyczył klucza podstawowego (próbowałem wstawić dwa wiersze z tym samym ProductId ). REPLACE opcja spowodowała, że ​​druga zastąpiła pierwszą.

Wycofanie

Inną opcją jest użycie ROLLBACK .

Ta opcja przerywa bieżącą instrukcję SQL z błędem SQLITE_CONSTRAINT i wycofuje bieżącą transakcję. Jeśli żadna transakcja nie jest aktywna (inna niż dorozumiana transakcja, która jest tworzona przy każdym poleceniu), to działa tak samo jak ABORT algorytm.

Oto przykład, który używa wielu INSERT OR ROLLBACK wyciągi w ramach transakcji.

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;

Oto pełne dane wyjściowe z mojego terminala po uruchomieniu tego:

sqlite> DELETE FROM Products;
sqlite> 
sqlite> BEGIN TRANSACTION;
sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);
sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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 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     
----------  -----------  ----------
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

Doszło więc do naruszenia ograniczenia, a następnie wycofało transakcję. Następnie kolejne wiersze zostały przetworzone, a następnie COMMIT napotkano słowo kluczowe. Do tego czasu transakcja została już wycofana, więc pojawił się kolejny błąd informujący nas, że żadna transakcja nie była aktywna.

Oto, co się stanie, jeśli usunę go z transakcji.

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;

Oto pełne dane wyjściowe z mojego terminala po uruchomieniu tego:

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);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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 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       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      120.0     

W tym przypadku zadziałało to jak ABORT .

Aby potwierdzić, oto to samo oświadczenie przy użyciu ABORT zamiast 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;

Oto pełne dane wyjściowe z mojego terminala po uruchomieniu tego:

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);
Error: NOT NULL constraint failed: Products.ProductName
sqlite> 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 (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       9.99      
3           Saw          11.34     
4           Wrench       37.0      
5           Chisel       23.0      
6           Bandage      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. Jak działa SQLite Ifnull()

  2. Nie mogę ustawić wielu obrazów w widoku siatki?

  3. Android SQLite:Jak wygenerować dużą tabelę do celów testowych?

  4. Maksymalny rozmiar bazy danych SQLite w aplikacji na Androida

  5. Jak dodać miesiąc do daty w SQLite