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

Sådan fungerer ON CONFLICT i SQLite

SQLite har ON CONFLICT klausul, der giver dig mulighed for at specificere, hvordan begrænsningskonflikter skal håndteres. Det gælder for UNIQUE , NOT NULL , CHECK og PRIMARY KEY begrænsninger (men ikke FOREIGN KEY begrænsninger).

Der er fem mulige muligheder, du kan bruge med denne klausul:

  • ABORT
  • FAIL
  • IGNORE
  • REPLACE
  • ROLLBACK

Denne artikel giver eksempler og en forklaring på hver af disse muligheder.

ON CONFLICT klausul bruges i CREATE TABLE sætninger, men det kan også bruges ved indsættelse eller opdatering af data ved at erstatte ON CONFLICT med OR .

Når du opretter tabellen

Som nævnt kan du bruge ON CONFLICT når du opretter tabellen, eller når du indsætter/opdaterer data.

Her er et eksempel på brug af ON CONFLICT på tidspunktet for oprettelse af tabellen.

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

Når du bruger ON CONFLICT klausul, anvender du den til den specifikke begrænsning, du vil håndtere. I dette tilfælde tilføjede jeg klausulen til en NOT NULL begrænsning.

I dette tilfælde specificerede jeg IGNORE , hvilket betyder, at hvis der er en overtrædelse af en begrænsning, vil SQLite springe over den række og derefter fortsætte behandlingen.

Hvis jeg nu prøver at indsætte NULL ind i Produktnavn kolonne, den række springes over.

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 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Når du indsætter data

Du kan også bruge denne klausul, når du indsætter og opdaterer data. Forskellen er, at du erstatter ON CONFLICT med OR .

For at demonstrere vil jeg droppe den forrige tabel og oprette den igen, men uden ON CONFLICT klausul:

DROP TABLE IF EXISTS Products;

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

Nu vil jeg indsætte de samme data og bruge OR IGNORE for at springe over den række, der overtræder 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 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Så vi får det samme resultat som i det foregående eksempel.

I disse eksempler brugte jeg IGNORE mulighed. Dette er blot en af ​​fem mulige muligheder for denne klausul.

Nedenfor er eksempler, der bruger hver af de fem muligheder.

Afbryd

Denne indstilling afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl og fjerner eventuelle ændringer foretaget af den aktuelle SQL-sætning; men ændringer forårsaget af tidligere SQL-sætninger inden for samme transaktion bevares, og transaktionen forbliver aktiv.

Dette er standardadfærden. Det er med andre ord, hvad der sker under overtrædelser af begrænsninger, når du ikke bruger ON CONFLICT klausul.

Her er et eksempel på, hvad der sker, når du angiver 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:

 

Ingen resultater blev returneret, fordi INSERT operationen blev afbrudt, og bordet er derfor tomt.

Her er, hvad der sker, hvis jeg sætter hver række i sin egen INSERT erklæring 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 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Fejl

FAIL option afbryder den aktuelle SQL-sætning med en SQLITE_CONSTRAINT-fejl. Men det trækker ikke tilbage tidligere ændringer af SQL-sætningen, der mislykkedes, og det afslutter heller ikke transaktionen.

Her er et eksempel.

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 

Her er den i med separat INSERT opgørelser inden for 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 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Ignorer

IGNORE option springer den ene række over, der indeholder begrænsningsovertrædelsen, og fortsætter med at behandle efterfølgende rækker af SQL-sætningen, som om intet gik galt. Andre rækker før og efter rækken, der indeholdt begrænsningsovertrædelsen, indsættes eller opdateres normalt. Ingen fejl returneres for unikhed, NOT NULL og UNIQUE begrænsningsfejl, når denne mulighed bruges. Denne mulighed fungerer dog som ABORT for fejl med fremmednøgler.

De første eksempler på denne side bruger IGNORE , men her er 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 Hammer 9,99 3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120.0 

Erstat

REPLACE mulighed fungerer forskelligt afhængigt af overtrædelsen:

  • Når en UNIQUE eller PRIMARY KEY overtrædelse af restriktioner forekommer,, REPLACE option sletter allerede eksisterende rækker, der forårsager overtrædelsen af ​​begrænsningen, før den aktuelle række indsættes eller opdateres, og kommandoen fortsætter med at udføre normalt.
  • Hvis en NOT NULL overtrædelse af restriktioner, erstatter den NULL værdi med standardværdien for den kolonne, eller hvis kolonnen ikke har nogen standardværdi, så ABORT algoritme bruges.
  • Hvis en CHECK begrænsning eller fremmednøgle begrænsning opstår, derefter REPLACE fungerer som ABORT .

Desuden, hvis den sletter rækker for at opfylde en begrænsning, udløses sletning, hvis og kun hvis rekursive triggere er aktiveret.

Her er et eksempel, der bruger REPLACE mulighed.

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 Skruenøgle 37,0 2 Søm 1,49 3 Sav 11,34 5 Mejsel 23,0 6 Bandage 120.0 

I dette eksempel var konflikten med den primære nøgle (jeg forsøgte at indsætte to rækker med det samme ProductId ). REPLACE option fik den anden til at erstatte den første.

Tilbage

En anden mulighed er at bruge ROLLBACK .

Denne indstilling 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.

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

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

sqlite> SLET FRA produkter;sqlite> sqlite> BEGIN TRANSACTION;sqlite> INDSÆT ELLER TILBAGE TIL PRODUKTER VÆRDIER (1, 'Hammer', 9,99); Fejl:NOT NULL begrænsning mislykkedes:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34); sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Skruenøgle', 37.00 INSERTRO e> INSERTRO sqlite); INTO Products VALUES (5, 'Mejsel', 23.00);sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Fejl:kan ikke forpligte - ingen transaktion er aktivsqlite> sqlite> SELECT Produkter;ProductId ProductName Pris ---------- ----------- ----------3 Sav 11,34 4 Skruenøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0  

Så det kom til begrænsningsovertrædelsen og rullede derefter transaktionen tilbage. Derefter blev de efterfølgende 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', 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; 

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

sqlite> SLET FRA produkter;sqlite> sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (1, 'Hammer', 9,99);sqlite> INSERT ELLER ROLLBACK INTO Products VALUES (2, NULL, 1,49) fejl:mislykkedes:Products.ProductNamesqlite> INSERT OR ROLLBACK INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ROLLBACK INTO Products VALUES (4, 'Wrench', 37.00);sqlite> INSERT INTO ROLLs , 'Mejsel', 23.00);sqlite> INDSÆT ELLER TILBAGE TIL PRODUKTERVÆRDIER (6, 'Bandage', 120.00);sqlite> sqlite> VÆLG * FRA produkter;ProduktId Produktnavn Pris ---------- -- ---------- ----------1 Hammer 9,99 3 Sav 11,34 4 Nøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0 

I dette tilfælde virkede det som ABORT .

For at bekræfte, 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', 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; 

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

sqlite> DELETE FROM Products;sqlite> sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (1, 'Hammer', 9,99);sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (2, NULL, 1,49);Fejl:IKKE NULL-begrænsning mislykkedes:Products.ProductNamesqlite> INSERT OR AFBORT INTO Products VALUES (3, 'Saw', 11.34);sqlite> INSERT OR ABORT INTO Products VALUES (4, 'Skruenøgle', 37.00);sqlite> INSERT ELLER AFBRYD I (5 Products VALUES) , 'Mejsel', 23,00);sqlite> INDSÆT ELLER AFBRYD I PRODUKTERVÆRDIER (6, 'Bandage', 120,00);sqlite> sqlite> VÆLG * FRA produkter;ProduktId Produktnavn Pris ---------- -- ---------- ----------1 Hammer 9,99 3 Sav 11,34 4 Nøgle 37,0 5 Mejsel 23,0 6 Bandage 120,0 


  1. Sender SentryOne-data til Azure SQL Database DTU Calculator

  2. Hvordan ændrer jeg en MySQL-kolonne for at tillade NULL?

  3. mangler nøgleordsfejl i oracle CASE WHEN sql-sætning

  4. PostgreSQL-procesnavne på Solaris