sql >> Databasteknik >  >> RDS >> SQLite

Hantera primärnyckelkonflikter vid infogning av data i SQLite

SQLite har en icke-standardiserad SQL-tilläggssats som heter ON CONFLICT som gör det möjligt för oss att specificera hur vi ska hantera tvångskonflikter.

I synnerhet gäller klausulen UNIQUE , NOT NULL , CHECK och PRIMARY KEY begränsningar.

Den här artikeln ger exempel på hur den här klausulen kan användas för att avgöra hur konflikter med primärnyckelbegränsningar ska hanteras.

Med "konflikter med primärnyckelbegränsningar" menar jag när du försöker infoga ett dubblettvärde i en primärnyckelkolumn. Som standard, när du försöker göra detta, kommer operationen att avbrytas och SQLite returnerar ett fel.

Men du kan använda ON CONFLICT klausul för att ändra hur SQLite hanterar dessa situationer.

Ett alternativ är att använda denna sats i CREATE TABLE uttalande när du skapar tabellen. Att göra det kommer att avgöra hur alla INSERT operationer behandlas.

Ett annat alternativ är att använda satsen på INSERT uttalande när du försöker infoga data i tabellen. Detta gör att du kan dra fördel av klausulen även när tabellen inte skapades med den. När du använder det här alternativet är syntaxen annorlunda; du använder OR istället för ON CONFLICT .

Exemplen på den här sidan använder det andra alternativet – jag skapar tabellen utan koden ON CONFLICT sats, och jag anger istället ORINSERT uttalande.

Exempeltabell

Låt oss skapa en enkel tabell och lägga till en rad.

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

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

SELECT * FROM Products;

Resultat:

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

Vi har för närvarande en rad med ett ProductId av 1 .

Nu kan vi gå igenom de olika scenarierna för att infoga data i den tabellen som bryter mot den primära nyckelbegränsningen.

Exempel 1 – Avbryt (standardbeteende)

Som nämnts är standardbeteendet för SQLite att avbryta INSERT operation och returnerar ett fel.

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

Resultat:

Error: UNIQUE constraint failed: Products.ProductId

Ett fel returnerades och ingenting infogades.

Detta motsvarar att använda OR ABORT alternativ.

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

Resultat:

Error: UNIQUE constraint failed: Products.ProductId

Vi kan verifiera att inget har infogats genom att köra en SELECT uttalande mot bordet.

SELECT * FROM Products;

Resultat:

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

Vi kan se att tabellen bara innehåller den ursprungliga raden.

Exempel 2 – Ignorera

Ett alternativ är att låta SQLite ignorera den felande raden. Med andra ord hoppar den över raden och fortsätter att bearbeta efterföljande rader.

För att göra detta inom din INSERT uttalande, använd OR IGNORE .

Effekten av detta är att INSERT operationen lyckas, men utan några rader som bryter mot primärnyckelns begränsning.

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;

Resultat:

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

I det här fallet försökte jag infoga två nya rader med ett ID som redan fanns i tabellen, så båda dessa rader hoppades över.

Exempel 3 – Ersätt

Ett annat alternativ du har är att ersätta den ursprungliga raden med den nya raden.

Med andra ord kommer du att skriva över befintliga data med dina nya data.

För att göra detta, använd 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;

Resultat:

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

I det här fallet var de flesta rader desamma, så de innehåller samma data efter INSERT drift. Vi kan dock se att den första raden har uppdaterats för att använda värdena i min INSERT påstående.

Vi kan också se att den använde den andra uppsättningen värden (eftersom två delade samma ProductId ).

Så effekten är ungefär som en UPDATE uttalande och INSERT uttalande kombinerat.

Exempel 4 – Återställ

Ett annat alternativ är att använda ROLLBACK alternativ.

Detta avbryter den aktuella SQL-satsen med ett SQLITE_CONSTRAINT-fel och återställer den aktuella transaktionen. Om ingen transaktion är aktiv (annat än den underförstådda transaktionen som skapas på varje kommando) fungerar den på samma sätt som ABORT algoritm.

Det lönar sig att vara uppmärksam på hur detta alternativ fungerar. Här är ett exempel som använder flera INSERT OR ROLLBACK uttalanden i en transaktion.

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;

Här är hela resultatet från min terminal när jag kör detta:

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> 

Det som hände här är i princip att det har kommit så långt som till överträdelsen av begränsningen och sedan rullat tillbaka transaktionen. Sedan bearbetades de följande två raderna och sedan COMMIT sökord påträffades. Då hade transaktionen redan återställts och så vi fick ett nytt felmeddelande om att ingen transaktion var aktiv.

Det här är vad som händer om jag tar bort det från transaktionen.

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;

Här är hela resultatet från min terminal när jag kör detta:

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>

I det här fallet fungerade det som ABORT .

För att demonstrera detta, här är samma uttalande med ABORT istället för 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;

Här är hela resultatet från min terminal när jag kör detta:

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> 

Feilalternativet

FAIL alternativet avbryter den aktuella SQL-satsen med ett SQLITE_CONSTRAINT-fel. Men det här alternativet tar inte tillbaka tidigare ändringar av SQL-satsen som misslyckades och avslutar inte heller transaktionen.

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;

Resultat:

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

  1. Hur använder man en främmande nyckel i sqlite?

  2. Hur man korrekt infogar newline i nvarchar

  3. Hur man får den aktuella tiden (utan tidszon) i PostgreSQL

  4. SQLite returnerade en felkod på 14