Question 1Tu as écrit REFERENCES category(cat_id) sur une colonne, et pourtant une ligne pointant vers une catégorie inexistante est passée. Quelle est la cause la plus probable ?
Contraintes de clé étrangère et actions référentielles (ON DELETE / ON UPDATE)
Avec un montage parent/enfant category–item, apprends REFERENCES pour l'intégrité référentielle, pourquoi PRAGMA foreign_keys=ON est nécessaire pour activer les vérifications, et comment ON DELETE CASCADE / SET NULL / RESTRICT propagent chacun la suppression du parent — en pratique.
Les données qu'on utilise — category et item
Une contrainte de clé étrangère (la contrainte qui garantit que la valeur d'une colonne existe toujours comme clé primaire dans une autre table) est le mécanisme qui protège l'intégrité référentielle entre tables (l'état où chaque ligne référencée existe réellement).
Elle bloque des contradictions comme « un item pointe vers une catégorie inexistante » ou « supprimer une catégorie laisse ses items orphelins », côté base de données.
La vérification de clé étrangère s'active avec PRAGMA foreign_keys=ON
Les contraintes de clé étrangère se déclarent en écrivant REFERENCES table_parente(col_parente) dans la définition de colonne de la table enfant.
item.cat_id porte REFERENCES category(cat_id), qui encode la règle : chaque valeur item.cat_id doit exister dans category.
Cependant, dans la console de ce cours la vérification de clé étrangère est par défaut désactivée (PRAGMA foreign_keys vaut 0).
Tant qu'elle est désactivée, `REFERENCES` n'est pas réellement appliqué et des lignes pointant vers une catégorie inexistante peuvent être insérées.
Pour appliquer réellement la contrainte, exécute PRAGMA foreign_keys=ON; une fois par connexion.
-- Activer la vérification de clé étrangère
PRAGMA foreign_keys=ON;
-- Confirmer l'état (1 signifie activé)
PRAGMA foreign_keys;
-- Tenter d'insérer une ligne pointant vers cat_id=99 (absent de category)
-- Avec foreign_keys=ON, c'est rejeté avec FOREIGN KEY constraint failed
INSERT INTO item VALUES (5,'Mouse',99);
ON DELETE — que faire des lignes enfants quand une ligne parente est supprimée
Quand une ligne parente (category) est supprimée, qu'arrive-t-il aux lignes enfants (item) qui pointaient vers elle ? Tu décides en écrivant une action référentielle dans la clause REFERENCES.
Il existe trois actions référentielles courantes.
ON DELETE CASCADE signifie supprimer le parent supprime aussi les enfants (suppression en cascade), ON DELETE SET NULL signifie la colonne de référence de l'enfant est mise à NULL et la ligne est conservée, et ON DELETE RESTRICT signifie la suppression du parent elle-même est refusée tant que les enfants y font encore référence.
Si tu ne spécifies pas d'action, le comportement par défaut est aussi de type RESTRICT (un parent référencé ne peut pas être supprimé).
Le comportement approprié dépend du besoin métier.
| Action référentielle | Quand le parent category est supprimé | Ce qui arrive à l'enfant item |
|---|---|---|
| ON DELETE CASCADE | Supprimé | Les enfants sont supprimés en cascade avec lui |
| ON DELETE SET NULL | Supprimé | Les enfants restent, cat_id devient NULL |
| ON DELETE RESTRICT | Impossible à supprimer — erreur | La suppression du parent est refusée tant que des enfants existent (intacts) |
-- Exemple de déclaration avec ON DELETE SET NULL
CREATE TABLE cat_demo(cat_id INTEGER PRIMARY KEY, cat_name TEXT NOT NULL);
CREATE TABLE item_demo(
item_id INTEGER PRIMARY KEY,
item_name TEXT NOT NULL,
cat_id INTEGER REFERENCES cat_demo(cat_id) ON DELETE SET NULL
);
INSERT INTO cat_demo VALUES (1,'Stationery'),(2,'Electronics');
INSERT INTO item_demo VALUES (1,'Pen',1),(2,'Phone',2),(3,'Cable',2);
-- Supprimer le parent cat_id=2 met cat_id de Phone / Cable à NULL
DELETE FROM cat_demo WHERE cat_id=2;
SELECT item_id, item_name, cat_id FROM item_demo ORDER BY item_id;
SET NULL et RESTRICT — choisir entre conserver et refuser
ON DELETE SET NULL conserve la ligne enfant quand le parent est supprimé, en remplaçant simplement la colonne de référence par NULL.
Utilise-le quand tu ne veux pas supprimer l'enregistrement enfant lui-même, comme « garder l'item comme 'non classé' ».
Si la colonne de référence de l'enfant est NOT NULL, NULL ne peut pas y être écrit, donc les colonnes utilisées avec SET NULL doivent autoriser NULL.
ON DELETE RESTRICT refuse la suppression du parent elle-même tant que les enfants y font encore référence.
Utilise-le quand tu veux un comportement sûr en cas d'échec (ne pas accidentellement supprimer une ligne maître encore référencée).
Une fois que tu as supprimé ou réaffecté tous les enfants pour qu'aucune référence ne subsiste, le parent peut être supprimé.
Dans le prochain exercice, tu mettras en place SET NULL et RESTRICT côte à côte dans une console pour les comparer.
-- Exemple RESTRICT : un parent avec enfants ne peut pas être supprimé
CREATE TABLE cat_r(cat_id INTEGER PRIMARY KEY, cat_name TEXT NOT NULL);
CREATE TABLE item_r(
item_id INTEGER PRIMARY KEY,
item_name TEXT NOT NULL,
cat_id INTEGER REFERENCES cat_r(cat_id) ON DELETE RESTRICT
);
INSERT INTO cat_r VALUES (1,'Stationery'),(2,'Electronics');
INSERT INTO item_r VALUES (1,'Pen',1);
-- cat_id=1 est référencé par item_r, donc la suppression est refusée
DELETE FROM cat_r WHERE cat_id=1;
-- cat_id=2 n'a pas de références, donc il peut être supprimé
DELETE FROM cat_r WHERE cat_id=2;
SELECT * FROM cat_r ORDER BY cat_id;
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Quelle action référentielle cause la suppression automatique d'une ligne enfant quand sa ligne parente est supprimée ?
Question 3Quelle condition la colonne de référence de la table enfant doit-elle remplir pour utiliser ON DELETE SET NULL ?