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

Radzenie sobie z konfliktami kluczy podstawowych podczas wstawiania danych do SQLite

SQLite ma niestandardową klauzulę rozszerzenia SQL o nazwie ON CONFLICT to pozwala nam określić, jak radzić sobie z konfliktami ograniczeń.

W szczególności klauzula dotyczy UNIQUE , NOT NULL , CHECK i PRIMARY KEY ograniczenia.

Ten artykuł zawiera przykłady użycia tej klauzuli do określenia sposobu obsługi konfliktów ograniczeń klucza podstawowego.

Przez „konflikty klucza podstawowego” rozumiem, gdy próbujesz wstawić zduplikowaną wartość do kolumny klucza podstawowego. Domyślnie, gdy spróbujesz to zrobić, operacja zostanie przerwana, a SQLite zwróci błąd.

Ale możesz użyć ON CONFLICT klauzula zmieniająca sposób, w jaki SQLite radzi sobie z takimi sytuacjami.

Jedną z opcji jest użycie tej klauzuli w CREATE TABLE oświadczenie podczas tworzenia tabeli. Spowoduje to określenie, w jaki sposób wszystkie INSERT operacje są traktowane.

Inną opcją jest użycie klauzuli w INSERT oświadczenie za każdym razem, gdy próbujesz wstawić dane do tabeli. Dzięki temu możesz skorzystać z klauzuli, nawet jeśli tabela nie została z nią utworzona. Gdy używasz tej opcji, składnia jest inna; używasz OR zamiast ON CONFLICT .

Przykłady na tej stronie wykorzystują drugą opcję – tworzę tabelę bez ON CONFLICT i zamiast tego określam OR na INSERT oświadczenie.

Przykładowa tabela

Stwórzmy prostą tabelę i dodajmy jeden wiersz.

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

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

SELECT * FROM Products;

Wynik:

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

Obecnie mamy jeden wiersz z ProductId z 1 .

Teraz możemy przejść przez różne scenariusze wstawiania danych do tej tabeli, która narusza ograniczenie klucza podstawowego.

Przykład 1 – Przerwij (zachowanie domyślne)

Jak wspomniano, domyślnym zachowaniem SQLite jest przerwanie INSERT operacji i zwróć błąd.

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

Wynik:

Error: UNIQUE constraint failed: Products.ProductId

Zwrócono błąd i nic nie zostało wstawione.

Jest to odpowiednik użycia OR ABORT opcja.

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

Wynik:

Error: UNIQUE constraint failed: Products.ProductId

Możemy sprawdzić, czy nic nie zostało wstawione, uruchamiając SELECT oświadczenie przeciwko tabeli.

SELECT * FROM Products;

Wynik:

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

Widzimy, że tabela zawiera tylko oryginalny wiersz.

Przykład 2 – Ignoruj

Jedną z alternatyw jest skłonienie SQLite do ignorowania nieprawidłowego wiersza. Innymi słowy, pominie wiersz i będzie kontynuował przetwarzanie kolejnych wierszy.

Aby to zrobić w swoim INSERT oświadczenie, użyj OR IGNORE .

Efektem tego jest to, że INSERT operacja się powiodła, ale bez żadnych wierszy, które naruszają ograniczenie klucza podstawowego.

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;

Wynik:

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

W tym przypadku próbowałem wstawić dwa nowe wiersze z identyfikatorem, który już istniał w tabeli, więc oba te wiersze zostały pominięte.

Przykład 3 – Zamień

Inną dostępną opcją jest zastąpienie oryginalnego wiersza nowym wierszem.

Innymi słowy, zastąpisz istniejące dane nowymi danymi.

Aby to zrobić, użyj 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;

Wynik:

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

W tym przypadku większość wierszy była taka sama, więc zawierają te same dane po INSERT operacja. Widzimy jednak, że pierwszy wiersz został zaktualizowany, aby używał wartości w moim INSERT oświadczenie.

Widzimy również, że użył drugiego zestawu wartości (widząc, że dwa mają ten sam ProductId ).

Efekt jest więc trochę jak UPDATE oświadczenie i INSERT zestawienie połączone.

Przykład 4 – Wycofanie

Inną opcją jest użycie ROLLBACK opcja.

Powoduje to przerwanie bieżącej instrukcji SQL z błędem SQLITE_CONSTRAINT i wycofywanie bieżącej transakcji. 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.

Warto pamiętać o tym, jak działa ta opcja. 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', 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;

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

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> 

Zasadniczo doszło do tego, że doszło do naruszenia ograniczenia, a następnie wycofało transakcję. Następnie przetworzono kolejne dwie linie, 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', 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;

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', 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>

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

Aby to zademonstrować, oto ta sama instrukcja przy użyciu ABORT zamiast 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;

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', 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> 

Opcja niepowodzenia

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

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;

Wynik:

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. Zalecany sposób / polecenie odczytania danych z serwisu internetowego, przeanalizowania tych danych i wstawienia ich do bazy danych SQLite

  2. Baza danych SQLite wyświetla ostrzeżenie o automatycznym indeksowaniu <nazwa_tabeli>(kolumna) Po aktualizacji Androida L

  3. Jak działa SQLite Length()

  4. 2 sposoby na włączenie zawijania słów w SQLite

  5. Znaleziono wyciek bazy danych SQLite