sql >> Database teknologi >  >> RDS >> SQLite

Håndtering af primære nøglekonflikter ved indsættelse af data i SQLite

SQLite har en ikke-standard SQL-udvidelsesklausul kaldet ON CONFLICT der sætter os i stand til at specificere, hvordan vi skal håndtere begrænsningskonflikter.

Især gælder klausulen for UNIQUE , NOT NULL , CHECK og PRIMARY KEY begrænsninger.

Denne artikel giver eksempler på, hvordan denne klausul kan bruges til at bestemme, hvordan man håndterer primærnøglekonflikter.

Med "primære nøglekonflikter" mener jeg, når du forsøger at indsætte en dubletværdi i en primærnøglekolonne. Som standard, når du prøver at gøre dette, vil handlingen blive afbrudt, og SQLite vil returnere en fejl.

Men du kan bruge ON CONFLICT klausul for at ændre den måde, SQLite håndterer disse situationer på.

En mulighed er at bruge denne klausul i CREATE TABLE udsagn, når du laver tabellen. Hvis du gør det, vil det afgøre, hvordan alle INSERT operationer behandles.

En anden mulighed er at bruge klausulen på INSERT sætning, når du forsøger at indsætte data i tabellen. Dette giver dig mulighed for at drage fordel af klausulen, selv når tabellen ikke blev oprettet med den. Når du bruger denne mulighed, er syntaksen anderledes; du bruger OR i stedet for ON CONFLICT .

Eksemplerne på denne side bruger den anden mulighed – jeg opretter tabellen uden koden ON CONFLICT klausul, og jeg angiver i stedet ORINSERT erklæring.

Eksempeltabel

Lad os oprette en simpel tabel og tilføje en række.

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 i øjeblikket én række med et ProductId af 1 .

Nu kan vi gennemgå de forskellige scenarier med indsættelse af data i den tabel, der overtræder den primære nøglebegrænsning.

Eksempel 1 – Afbryd (standardadfærd)

Som nævnt er standardadfærden for SQLite at afbryde INSERT operation og returnerer en fejl.

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

Resultat:

Error: UNIQUE constraint failed: Products.ProductId

Der blev returneret en fejl, og der blev ikke indsat noget.

Dette svarer til at bruge OR ABORT mulighed.

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

Resultat:

Error: UNIQUE constraint failed: Products.ProductId

Vi kan bekræfte, at intet blev indsat ved at køre en SELECT udsagn mod bordet.

SELECT * FROM Products;

Resultat:

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

Vi kan se, at tabellen kun indeholder den oprindelige række.

Eksempel 2 – Ignorer

Et alternativ er at få SQLite til at ignorere den stødende række. Med andre ord vil den springe over rækken og fortsætte med at behandle efterfølgende rækker.

For at gøre dette i din INSERT sætning, brug OR IGNORE .

Effekten af ​​dette er, at INSERT handlingen lykkes, men uden nogen rækker, der overtræder den primære nøglebegræ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 dette tilfælde forsøgte jeg at indsætte to nye rækker med et ID, der allerede fandtes i tabellen, så begge disse rækker blev sprunget over.

Eksempel 3 – Erstat

En anden mulighed, du har, er at erstatte den oprindelige række med den nye række.

Du vil med andre ord overskrive de eksisterende data med dine nye data.

For at gøre dette skal du bruge 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 dette tilfælde var de fleste rækker de samme, så de indeholder de samme data efter INSERT operation. Vi kan dog se, at den første række er blevet opdateret til at bruge værdierne i min INSERT udmelding.

Vi kan også se, at den brugte det andet sæt værdier (eftersom to delte det samme ProductId ).

Så effekten er lidt ligesom en UPDATE sætning og INSERT erklæring kombineret.

Eksempel 4 – Tilbageførsel

En anden mulighed er at bruge ROLLBACK mulighed.

Dette afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl og ruller den aktuelle transaktion tilbage. Hvis ingen transaktion er aktiv (ud over den underforståede transaktion, der oprettes på hver kommando), fungerer den på samme måde som ABORT algoritme.

Det betaler sig at være opmærksom på, hvordan denne mulighed fungerer. Her er et eksempel, der bruger flere INSERT OR ROLLBACK opgørelser inden for 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;

Her er det fulde output fra min terminal, når jeg kører dette:

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> 

Grundlæggende er det, der skete her, at det er nået så langt som overtrædelsen af ​​begrænsningen, og derefter rullede transaktionen tilbage. Derefter blev de næste to linjer behandlet og derefter COMMIT søgeord blev stødt på. På det tidspunkt var transaktionen allerede blevet rullet tilbage, så vi fik endnu en fejl, der fortalte os, at ingen transaktion var aktiv.

Her er, hvad der sker, hvis jeg fjerner det fra 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;

Her er det fulde output fra min terminal, når jeg kører dette:

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 dette tilfælde virkede det som ABORT .

For at demonstrere dette, her er den samme erklæring ved hjælp af ABORT i stedet for 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;

Her er det fulde output fra min terminal, når jeg kører dette:

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> 

Fejlmuligheden

FAIL option afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl. Men denne mulighed trækker ikke tilbage tidligere ændringer af SQL-sætningen, der mislykkedes, og den afslutter heller ikke 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. Oracle JDBC intermitterende forbindelsesproblem

  2. FLOSS UK forårskonference

  3. Find refererede enheder i SQL Server:sys.dm_sql_referenced_entities

  4. T-sql - afgør om værdien er heltal