SQLite a le ON CONFLICT
clause qui vous permet de spécifier comment gérer les conflits de contraintes. Il s'applique à UNIQUE
, NOT NULL
, CHECK
, et PRIMARY KEY
contraintes (mais pas FOREIGN KEY
contraintes).
Il existe cinq options possibles que vous pouvez utiliser avec cette clause :
ABORT
FAIL
IGNORE
REPLACE
ROLLBACK
Cet article fournit des exemples et une explication de chacune de ces options.
Le ON CONFLICT
la clause est utilisée dans CREATE TABLE
déclarations, mais il peut également être utilisé lors de l'insertion ou de la mise à jour de données en remplaçant ON CONFLICT
avec OR
.
Lors de la création du tableau
Comme mentionné, vous pouvez utiliser ON CONFLICT
lorsque vous créez la table ou lorsque vous insérez/mettez à jour des données.
Voici un exemple d'utilisation de ON CONFLICT
au moment de la création du tableau.
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL ON CONFLICT IGNORE,
Price
);
Lorsque vous utilisez le ON CONFLICT
clause, vous l'appliquez à la contrainte spécifique que vous souhaitez gérer. Dans ce cas, j'ai ajouté la clause à un NOT NULL
contrainte.
Dans ce cas, j'ai spécifié IGNORE
, ce qui signifie que, s'il y a une violation de contrainte, SQLite ignorera cette ligne, puis poursuivra le traitement.
Maintenant, si j'essaie d'insérer NULL
dans le ProductName colonne cette ligne est ignorée.
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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99 3 Scie 11,34 4 Clé 37,0 5 Burin 23,0 6 Bandage 120.0
Lors de l'insertion de données
Vous pouvez également utiliser cette clause lors de l'insertion et de la mise à jour des données. La différence est que vous remplacez ON CONFLICT
avec OR
.
Pour illustrer, je vais supprimer la table précédente et la recréer, mais sans le ON CONFLICT
clause :
DROP TABLE IF EXISTS Products;
CREATE TABLE Products(
ProductId INTEGER PRIMARY KEY,
ProductName NOT NULL,
Price
);
Maintenant, je vais insérer les mêmes données et utiliser OR IGNORE
pour ignorer la ligne qui viole la contrainte.
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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99 3 Scie 11,34 4 Clé 37,0 5 Burin 23,0 6 Bandage 120.0
Nous obtenons donc le même résultat que dans l'exemple précédent.
Dans ces exemples, j'ai utilisé le IGNORE
option. Ce n'est qu'une des cinq options possibles pour cette clause.
Vous trouverez ci-dessous des exemples utilisant chacune des cinq options.
Annuler
Cette option abandonne l'instruction SQL en cours avec une erreur SQLITE_CONSTRAINT et annule toutes les modifications apportées par l'instruction SQL en cours; mais les modifications causées par les instructions SQL précédentes dans la même transaction sont conservées et la transaction reste active.
C'est le comportement par défaut. En d'autres termes, c'est ce qui se passe lors de violations de contraintes lorsque vous n'utilisez pas le ON CONFLICT
clause.
Voici un exemple de ce qui se passe lorsque vous spécifiez 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;
Résultat :
Aucun résultat n'a été renvoyé car le
INSERT
l'opération a été abandonnée, et la table est donc vide.Voici ce qui se passe si je mets chaque ligne dans son propre
INSERT
déclaration dans une transaction.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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99 3 Scie 11,34 4 Clé 37,0 5 Burin 23,0 6 Bandage 120.0Échec
Le
FAIL
L'option abandonne l'instruction SQL en cours avec une erreur SQLITE_CONSTRAINT. Mais il n'annule pas les modifications précédentes de l'instruction SQL qui a échoué et ne met pas fin à la transaction.Voici un exemple.
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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99Le voici avec
INSERT
séparé relevés dans une transaction.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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99 3 Scie 11,34 4 Clé 37,0 5 Burin 23,0 6 Bandage 120.0Ignorer
Le
IGNORE
L'option ignore la ligne qui contient la violation de contrainte et continue de traiter les lignes suivantes de l'instruction SQL comme si de rien n'était. Les autres lignes avant et après la ligne contenant la violation de contrainte sont insérées ou mises à jour normalement. Aucune erreur n'est renvoyée pour l'unicité,NOT NULL
, etUNIQUE
erreurs de contrainte lorsque cette option est utilisée. Cependant, cette option fonctionne commeABORT
pour les erreurs de contrainte de clé étrangère.Les premiers exemples sur cette page utilisent
IGNORE
, mais le revoilà.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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Marteau 9,99 3 Scie 11,34 4 Clé 37,0 5 Burin 23,0 6 Bandage 120.0Remplacer
Le
REPLACE
l'option fonctionne différemment selon la violation :
- Quand un
UNIQUE
ouPRIMARY KEY
une violation de contrainte se produit, leREPLACE
L'option supprime les lignes préexistantes à l'origine de la violation de la contrainte avant d'insérer ou de mettre à jour la ligne actuelle et la commande continue de s'exécuter normalement. - Si un
NOT NULL
une violation de contrainte se produit, elle remplace leNULL
value avec la valeur par défaut pour cette colonne, ou si la colonne n'a pas de valeur par défaut, alors leABORT
algorithme est utilisé. - Si un
CHECK
une violation de contrainte ou de contrainte de clé étrangère se produit, alorsREPLACE
fonctionne commeABORT
.
De plus, s'il supprime des lignes afin de satisfaire une contrainte, les déclencheurs de suppression se déclenchent si et seulement si les déclencheurs récursifs sont activés.
Voici un exemple qui utilise le REPLACE
option.
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;
Résultat :
ProductId ProductName Prix ---------- ----------- ----------1 Clé 37,0 2 Clous 1,49 3 Scie 11,34 5 Ciseau 23,0 6 Bandage 120.0
Dans cet exemple, le conflit était avec la clé primaire (j'ai essayé d'insérer deux lignes avec le même ProductId ). Le REPLACE
option a fait que le second a remplacé le premier.
Rollback
Une autre option consiste à utiliser ROLLBACK
.
Cette option annule l'instruction SQL en cours avec une erreur SQLITE_CONSTRAINT et annule la transaction en cours. Si aucune transaction n'est active (autre que la transaction implicite créée sur chaque commande), cela fonctionne de la même manière que ABORT
algorithme.
Voici un exemple qui utilise plusieurs INSERT OR ROLLBACK
relevés dans une transaction.
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;
Voici la sortie complète de mon terminal lorsque j'exécute ceci :
sqlite> DELETE FROM Products;sqlite> sqlite> BEGIN TRANSACTION;sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49); Erreur :La contrainte NOT NULL a échoué :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 OR ROLLBACK INTO Products VALUES (5, 'Chisel', 23.00);sqlite> INSERT OR ROLLBACK INTO Products VALUES (6, 'Bandage', 120.00);sqlite> COMMIT;Erreur :impossible de valider - aucune transaction n'est activesqlite> sqlite> SELECT * FROM Products;ProductId ProductName Prix ---------- ----------- ----------3 Scie 11,34 4 Clé 37,0 5 Ciseau 23,0 6 Bandage 120,0Il est donc arrivé à la violation de contrainte, puis a annulé la transaction. Ensuite, les lignes suivantes ont été traitées, puis le
COMMIT
mot clé a été rencontré. À ce moment-là, la transaction avait déjà été annulée et nous avons donc reçu une autre erreur nous indiquant qu'aucune transaction n'était active.Voici ce qui se passe si je le supprime de la transaction.
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;
Voici la sortie complète de mon terminal lorsque j'exécute ceci :
sqlite> DELETE FROM Products;sqlite> sqlite> INSERT OR ROLLBACK INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ROLLBACK INTO Products VALUES (2, NULL, 1.49);Erreur :contrainte NOT NULL échec :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 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 Marteau 9.99 3 Scie 11.34 4 Clé 37.0 5 Ciseau 23.0 6 Bandage 120.0Dans ce cas, cela a fonctionné comme
ABORT
.Pour confirmer, voici la même déclaration en utilisant
ABORT
au lieu deROLLBACK
.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;
Voici la sortie complète de mon terminal lorsque j'exécute ceci :
sqlite> DELETE FROM Products;sqlite> sqlite> INSERT OR ABORT INTO Products VALUES (1, 'Hammer', 9.99);sqlite> INSERT OR ABORT INTO Products VALUES (2, NULL, 1.49);Erreur :contrainte NOT NULL échoué :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 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 Marteau 9.99 3 Scie 11.34 4 Clé 37.0 5 Ciseau 23.0 6 Bandage 120.0