SQLite
 sql >> Base de données >  >> RDS >> SQLite

Comment ON CONFLICT fonctionne dans SQLite

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,99 

Le 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.0 

Ignorer

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 , et UNIQUE erreurs de contrainte lorsque cette option est utilisée. Cependant, cette option fonctionne comme ABORT 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.0 

Remplacer

Le REPLACE l'option fonctionne différemment selon la violation :

  • Quand un UNIQUE ou PRIMARY KEY une violation de contrainte se produit, le REPLACE 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 le NULL value avec la valeur par défaut pour cette colonne, ou si la colonne n'a pas de valeur par défaut, alors le ABORT algorithme est utilisé.
  • Si un CHECK une violation de contrainte ou de contrainte de clé étrangère se produit, alors REPLACE fonctionne comme ABORT .

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,0  

Il 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.0 

Dans ce cas, cela a fonctionné comme ABORT .

Pour confirmer, voici la même déclaration en utilisant ABORT au lieu de 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; 

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