Imaginez un formulaire administratif : certaines cases sont obligatoires (NOT NULL), certaines doivent être uniques comme le numéro de sécurité sociale (UNIQUE), d'autres doivent respecter un format (CHECK). Les contraintes SQL sont les "règles du formulaire" de votre base de données.

Schéma des 6 contraintes avec icônes (assisté par Nanao Banana 2)
2. Pourquoi utiliser les contraintes ?
Avantage n°1 : Qualité des données garantie
Les contraintes empêchent les données invalides d'entrer dans la base. C'est une couche de protection au niveau base de données, indépendante de l'application.
Avantage n°2 : Documentation vivante
Les contraintes documentent directement les règles métier dans le schéma. Un développeur qui découvre la base comprend immédiatement : "ce champ est obligatoire", "cette valeur doit être unique", etc.
Avantage n°3 : Performance
Les contraintes (surtout PRIMARY KEY et UNIQUE) créent automatiquement des index, accélérant les recherches.
Avantage n°4 : Centralisation des règles
Plutôt que de vérifier les règles dans chaque application qui accède à la base (API, script, interface admin), une seule définition au bon endroit.
3. NOT NULL : l'obligation de présence
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100) NOT NULL, -- Obligatoire
email VARCHAR(100), -- Optionnel (peut être NULL)
age INT -- Optionnel
);
-- ✅ VALIDE
INSERT INTO clients (id, nom) VALUES (1, 'Dupont');
-- ❌ ERREUR - nom ne peut pas être NULL
INSERT INTO clients (id) VALUES (2);
Quand l'utiliser : Pour toutes les données essentielles à l'enregistrement : nom, identifiant métier, date de création, etc.
''. Une chaîne vide est une valeur, NULL est l'absence de valeur. NOT NULL bloque NULL mais autorise '' (sauf contrainte CHECK supplémentaire).4. UNIQUE : l'interdiction de doublon
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100),
email VARCHAR(100) UNIQUE, -- Email unique dans toute la table
telephone VARCHAR(20) UNIQUE -- Téléphone unique aussi
);
-- ✅ VALIDE
INSERT INTO clients (id, nom, email) VALUES (1, 'Dupont', Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. ');
-- ❌ ERREUR - email déjà utilisé
INSERT INTO clients (id, nom, email) VALUES (2, 'Martin', Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. ');
Contrainte UNIQUE composite (plusieurs colonnes)
CREATE TABLE commandes (
id INT PRIMARY KEY,
client_id INT,
produit_id INT,
UNIQUE (client_id, produit_id) -- Un même client ne peut pas commander deux fois le même produit
);
Particularité NULL : La plupart des SGBD autorisent plusieurs NULL sur une colonne UNIQUE (car NULL ≠ NULL). Vérifiez le comportement de votre SGBD.

Illustration de la contrainte UNIQUE (assisté par Nanao Banana 2)
5. PRIMARY KEY : l'identifiant unique
La clé primaire est le mariage de NOT NULL et UNIQUE. Chaque table ne peut avoir qu'une seule PRIMARY KEY.
-- Syntaxe 1 : sur une colonne
CREATE TABLE clients (
id INT PRIMARY KEY, -- Unique, non NULL, indexé
nom VARCHAR(100)
);
-- Syntaxe 2 : sur plusieurs colonnes (clé composite)
CREATE TABLE lignes_commande (
commande_id INT,
produit_id INT,
quantite INT,
PRIMARY KEY (commande_id, produit_id) -- Le couple est unique
);
-- Syntaxe 3 : avec nom explicite
CREATE TABLE clients (
id INT,
nom VARCHAR(100),
CONSTRAINT pk_clients PRIMARY KEY (id)
);
- Privilégiez un identifiant technique (auto-incrémenté, UUID) plutôt qu'une donnée métier (qui pourrait changer).
- Les clés composites sont utiles mais peuvent complexifier les jointures.
- Toute table devrait avoir une PRIMARY KEY.
6. FOREIGN KEY : le lien entre tables
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100)
);
CREATE TABLE commandes (
id INT PRIMARY KEY,
client_id INT,
montant DECIMAL(10,2),
CONSTRAINT fk_commandes_client
FOREIGN KEY (client_id)
REFERENCES clients(id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
-- ❌ ERREUR - client_id 999 n'existe pas dans clients
INSERT INTO commandes (id, client_id, montant) VALUES (1, 999, 100.00);
- CASCADE : supprime les enfants automatiquement
- RESTRICT / NO ACTION : bloque la suppression du parent
- SET NULL : conserve les enfants sans lien (colonne nullable)
- SET DEFAULT : affecte une valeur par défaut
Pour approfondir, consultez le guide complet sur la suppression en cascade.
7. CHECK : la validation personnalisée
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100),
age INT CHECK (age >= 18 AND age <= 120), -- Âge entre 18 et 120 ans
email VARCHAR(100),
code_postal VARCHAR(5) CHECK (code_postal ~ '^[0-9]{5}$'), -- Format 5 chiffres
date_creation DATE DEFAULT CURRENT_DATE,
CONSTRAINT chk_email CHECK (email LIKE '%@%') -- Email doit contenir @
);
-- ✅ VALIDE
INSERT INTO clients (id, nom, age, email) VALUES (1, 'Dupont', 35, Cette adresse e-mail est protégée contre les robots spammeurs. Vous devez activer le JavaScript pour la visualiser. ');
-- ❌ ERREUR - age 15 (< 18)
INSERT INTO clients (id, nom, age) VALUES (2, 'Martin', 15);
-- ❌ ERREUR - email sans @
INSERT INTO clients (id, nom, email) VALUES (3, 'Durand', 'pasunemail');
8. DEFAULT : la valeur par défaut
CREATE TABLE clients (
id INT PRIMARY KEY,
nom VARCHAR(100),
statut VARCHAR(20) DEFAULT 'actif', -- Par défaut 'actif'
date_inscription DATE DEFAULT CURRENT_DATE, -- Date du jour
actif BOOLEAN DEFAULT TRUE,
points INT DEFAULT 0
);
-- ✅ VALIDE - statut sera 'actif', date_inscription aujourd'hui
INSERT INTO clients (id, nom) VALUES (1, 'Dupont');
-- ✅ On peut aussi surcharger
INSERT INTO clients (id, nom, statut) VALUES (2, 'Martin', 'suspendu');
Fonctions usuelles pour DEFAULT :
CURRENT_DATE/NOW(): date/heure couranteCURRENT_USER: utilisateur courant (PostgreSQL)UUID()/GEN_RANDOM_UUID(): identifiant unique0,1,'actif',TRUE: valeurs statiques

Illustration de DEFAULT sur plusieurs colonnes (assisté par Nanao Banana 2)
9. Comparatif des 6 contraintes
| Contrainte | Empêche | Garantit | Index automatique |
|---|---|---|---|
| NOT NULL | NULL | Colonne toujours remplie | Non |
| UNIQUE | Doublons | Valeurs toutes différentes | Oui |
| PRIMARY KEY | NULL + doublons | Identifiant unique et obligatoire | Oui |
| FOREIGN KEY | Orphelins | Lien valide entre tables | Variable (recommandé manuellement) |
| CHECK | Données hors condition | Règle métier personnalisée | Non |
| DEFAULT | (N'interdit rien, fournit une valeur) | Valeur par défaut si non spécifiée | Non |
10. Bonnes pratiques pour les contraintes
1. Nommez toujours vos contraintes
CONSTRAINT pk_clients PRIMARY KEY (id) plutôt que laisser un nom auto-généré. Facilite la maintenance et les modifications futures.
2. Une seule PRIMARY KEY par table
Une table ne peut avoir qu'une seule clé primaire. Pour plusieurs identifiants uniques, utilisez UNIQUE.
3. FOREIGN KEY = toujours nommée
Les FK sont les contraintes qu'on modifie le plus souvent. Un nom explicite (fk_commandes_clients) est indispensable.
4. Documentez les CHECK complexes
Les conditions CHECK peuvent devenir complexes. Ajoutez un commentaire SQL ou documentez dans le schéma.
5. Testez les contraintes en développement
Avant la mise en production, testez systématiquement que les contraintes rejettent bien les données invalides.
pk_[table]pour PRIMARY KEYfk_[table_enfant]_[table_parent]pour FOREIGN KEYuk_[table]_[colonne(s)]pour UNIQUEchk_[table]_[condition]pour CHECK
11. Erreurs fréquentes et solutions
Erreur 1 : NULL dans une colonne NOT NULL
ERROR: null value in column "nom" violates not-null constraint
Solution : Fournissez une valeur pour la colonne obligatoire ou ajoutez une valeur par défaut avec DEFAULT.
Erreur 2 : Doublon sur colonne UNIQUE
ERROR: duplicate key value violates unique constraint
Solution : Vérifiez avant insertion, ou utilisez ON CONFLICT (PostgreSQL) / INSERT IGNORE (MySQL).
Erreur 3 : Foreign key constraint fails
ERROR: insert or update on table "commandes" violates foreign key constraint
Solution : Insérez d'abord le parent, ou désactivez temporairement (déconseillé en production).
Erreur 4 : CHECK constraint violation
ERROR: new row for relation "clients" violates check constraint "chk_clients_age"
Solution : Vérifiez que la valeur respecte la condition, ou ajustez la contrainte.
SHOW CREATE TABLE nom_table (MySQL) ou \d nom_table (PostgreSQL) pour voir toutes les contraintes existantes.12. FAQ — Contraintes SQL
Peut-on ajouter une contrainte après la création de la table ?
Oui, avec ALTER TABLE. Exemple : ALTER TABLE clients ADD CONSTRAINT chk_age CHECK (age >= 18); Attention : si des données existantes violent la contrainte, l'opération échouera. Nettoyez d'abord les données invalides.
Une colonne peut-elle avoir plusieurs contraintes ?
Oui, bien sûr. Exemple : email VARCHAR(100) NOT NULL UNIQUE → obligatoire ET unique. On peut aussi cumuler NOT NULL, UNIQUE, CHECK, DEFAULT sur la même colonne.
Quelle est la différence entre UNIQUE et PRIMARY KEY ?
Une table ne peut avoir qu'une seule PRIMARY KEY, mais plusieurs contraintes UNIQUE. PRIMARY KEY interdit NULL, UNIQUE l'autorise (généralement). PRIMARY KEY est automatiquement indexée ; UNIQUE aussi mais l'index peut être non-cluster selon SGBD.
Les contraintes ralentissent-elles les insertions ?
Oui, légèrement. Chaque insertion vérifie les contraintes (recherche d'unicité, vérification CHECK, existence du parent pour FK). Le coût est généralement acceptable par rapport au bénéfice (données propres). Pour des imports massifs, on peut désactiver temporairement les contraintes, puis les réactiver.
Comment lister toutes les contraintes d'une table ?
MySQL : SHOW CREATE TABLE nom_table; ou SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'nom_table';
PostgreSQL : \d nom_table ou SELECT * FROM information_schema.table_constraints WHERE table_name = 'nom_table';
SQL Server : sp_help 'nom_table';
Existe-t-il d'autres contraintes moins connues ?
Oui : EXCLUDE (PostgreSQL) pour des exclusions complexes, FOREIGN KEY avec MATCH FULL/PARTIAL/SIMPLE, DEFERRABLE pour différer les vérifications. Mais les 6 présentées couvrent 99% des besoins.
13. Conclusion
Les contraintes SQL sont les gardiennes de votre base de données. Elles garantissent que seules des données valides, cohérentes et complètes y entrent. Une base bien contrainte est une base fiable.
Récapitulatif des 6 contraintes
- NOT NULL : champ obligatoire
- UNIQUE : pas de doublon
- PRIMARY KEY : identifiant unique et obligatoire
- FOREIGN KEY : lien valide entre tables
- CHECK : règle métier personnalisée
- DEFAULT : valeur par défaut