sql >> Databasteknik >  >> RDS >> SQLite

Hur ON CONFLICT fungerar i SQLite

SQLite har ON CONFLICT klausul som låter dig specificera hur begränsningskonflikter ska hanteras. Det gäller UNIQUE , NOT NULL , CHECK och PRIMARY KEY begränsningar (men inte FOREIGN KEY begränsningar).

Det finns fem möjliga alternativ du kan använda med denna sats:

  • ABORT
  • FAIL
  • IGNORE
  • REPLACE
  • ROLLBACK

Den här artikeln ger exempel och en förklaring av vart och ett av dessa alternativ.

ON CONFLICT sats används i CREATE TABLE satser, men det kan också användas när du infogar eller uppdaterar data genom att ersätta ON CONFLICT med OR .

När du skapar tabellen

Som nämnts kan du använda ON CONFLICT när du skapar tabellen eller när du infogar/uppdaterar data.

Här är ett exempel på hur du använder ON CONFLICT vid tidpunkten för att skapa tabellen.

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

När du använder ON CONFLICT klausul tillämpar du den på den specifika begränsningen som du vill hantera. I det här fallet lade jag till satsen till en NOT NULL begränsning.

I det här fallet angav jag IGNORE , vilket innebär att om det finns en begränsningsöverträdelse kommer SQLite att hoppa över den raden och sedan fortsätta bearbetningen.

Om jag nu försöker infoga NULL i Produktnamn kolumnen den raden hoppas över.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120.0 

När du infogar data

Du kan också använda den här klausulen när du infogar och uppdaterar data. Skillnaden är att du byter ut ON CONFLICT med OR .

För att demonstrera släpper jag den föregående tabellen och skapar den igen, men utan ON CONFLICT klausul:

DROP TABLE IF EXISTS Products;

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

Nu ska jag infoga samma data och använda OR IGNORE för att hoppa över raden som bryter mot begränsningen.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Så vi får samma resultat som i föregående exempel.

I dessa exempel använde jag IGNORE alternativ. Detta är bara ett av fem möjliga alternativ för denna klausul.

Nedan finns exempel med vart och ett av de fem alternativen.

Avbryt

Detta alternativ avbryter den aktuella SQL-satsen med ett SQLITE_CONSTRAINT-fel och backar ut alla ändringar som gjorts av den aktuella SQL-satsen; men ändringar orsakade av tidigare SQL-satser inom samma transaktion bevaras och transaktionen förblir aktiv.

Detta är standardbeteendet. Med andra ord, detta är vad som händer vid överträdelser av begränsningar när du inte använder ON CONFLICT klausul.

Här är ett exempel på vad som händer när du anger 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; 

Resultat:

 

Inga resultat returnerades eftersom INSERT operationen avbröts och tabellen är därför tom.

Här är vad som händer om jag lägger varje rad i sin egen INSERT uttalande i en transaktion.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Fel

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

Här är ett exempel.

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; 

Resultat:

ProductId ProductName Pris ---------- ---------- ----------1 Hammer 9,99 

Här är den in med separat INSERT uttalanden i en transaktion.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Ignorera

IGNORE alternativet hoppar över den ena raden som innehåller begränsningsöverträdelsen och fortsätter att bearbeta efterföljande rader i SQL-satsen som om inget gick fel. Andra rader före och efter raden som innehöll begränsningsöverträdelsen infogas eller uppdateras normalt. Inget fel returneras för unikhet, NOT NULL och UNIQUE begränsningsfel när detta alternativ används. Det här alternativet fungerar dock som ABORT för främmande nyckelbegränsningsfel.

De första exemplen på den här sidan använder IGNORE , men här är den igen.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Ersätt

REPLACE alternativet fungerar olika beroende på överträdelsen:

  • När en UNIQUE eller PRIMARY KEY begränsningsöverträdelse inträffar,, REPLACE alternativet tar bort redan existerande rader som orsakar begränsningsöverträdelsen innan den aktuella raden infogas eller uppdateras och kommandot fortsätter att köras normalt.
  • Om en NOT NULL begränsningsöverträdelse inträffar, den ersätter NULL värde med standardvärdet för den kolumnen, eller om kolumnen inte har något standardvärde, då ABORT algoritm används.
  • Om en CHECK begränsning eller främmande nyckel begränsning sker, sedan REPLACE fungerar som ABORT .

Om den tar bort rader för att uppfylla en begränsning, utlöses utlösare om och endast om rekursiva utlösare är aktiverade.

Här är ett exempel som använder REPLACE alternativ.

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; 

Resultat:

ProductId ProductName Pris ---------- ------------------ ----------1 Skiftnyckel 37,0 2 Spikar 1,49 3 Såg 11,34 5 Mejsel 23,0 6 Bandage 120.0 

I det här exemplet var konflikten med primärnyckeln (jag försökte infoga två rader med samma ProductId ). REPLACE alternativet fick den andra att ersätta den första.

Återställ

Ett annat alternativ är att använda ROLLBACK .

Det här alternativet 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.

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

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

sqlite> DELETE FROM Products;sqlite> sqlite> BÖRJA TRANSAKTION;sqlite> INFOGA ELLER ÅTERBAKA IN I produkter VÄRDEN (1, 'Hammer', 9,99);sqlite> INFOGA ELLER ÅTERVÄNDA INTO Products VALUES, (1,499); Fel:NOT NULL-begränsning misslyckades:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00 INSERTRO INSERTROe> INTO Products VALUES (5, 'Mejsel', 23.00);sqlite> INFOGA ELLER ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Fel:kan inte begå - ingen transaktion är aktivsqlite> sqlite> SELECT Produkter;ProductId Produktnamn Pris ---------- ------------------ ----------3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120,0  

Så det kom till begränsningsöverträdelsen och återställde sedan transaktionen. Sedan bearbetades de efterföljande 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', 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; 

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

sqlite> DELETE FROM Products;sqlite> sqlite> INFOGA ELLER ÅTERLÄMNA I PRODUKTERVÄRDEN (1, 'Hammer', 9,99);sqlite> INFOGA ELLER ÅTERBAKA INTO PRODUKTERVÄRDEN (2, NULL, 1,49); fel:int:misslyckades:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);sqlite> INSERT INTO ROLLs , 'Mejsel', 23.00);sqlite> INFOGA ELLER ÅTERBAKA IN I Products VALUES (6, 'Bandage', 120.00);sqlite> sqlite> VÄLJ * FRÅN Produkter;ProductId Produktnamn Pris ---------- -- ---------- ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120,0 

I det här fallet fungerade det som ABORT .

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

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

sqlite> DELETE FROM Products;sqlite> sqlite> INFOGA ELLER AVBRYT I PRODUKTERVÄRDEN (1, 'Hammer', 9,99);sqlite> INFOGA ELLER AVBRYTA I PRODUKTERVÄRDEN (2, NULL, 1,49);Fel:INTE NULL-begränsning misslyckades: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 ABORT INTO (5 Products VALUES) , 'Mejsel', 23.00);sqlite> INFOGA ELLER AVBRYT I PRODUKTS VÄRDEN (6, 'Bandage', 120.00);sqlite> sqlite> VÄLJ * FRA produkter;ProductId Produktnamn Pris ---------- -- ---------- ----------1 Hammare 9,99 3 Såg 11,34 4 Skiftnyckel 37,0 5 Mejsel 23,0 6 Bandage 120,0 


  1. MySQL VARCHAR Lengths och UTF-8

  2. Lista alla tabeller i postgresql informationsschema

  3. En nybörjarguide till SQL-tabeller

  4. Exportera MySQL-data till Excel i PHP