OUJOOD.COM
Définition de la valeur NULL en SQL
En SQL, NULL ne représente pas un zéro, ni une chaîne vide, ni la valeur « faux ». NULL signifie : aucune donnée. La case est vide parce que l'information est inconnue, non applicable, ou pas encore saisie — une distinction posée par Edgar F. Codd dès les fondements du modèle relationnel.
La conséquence directe : NULL n'est égal à rien, pas même à lui-même. Toute comparaison via = ou != retourne UNKNOWN, pas TRUE ni FALSE. C'est la logique ternaire du SQL standard (SQL:2023), et c'est là que naissent la plupart des bugs silencieux.
Quand NULL apparaît dans une base de données
Trois situations reviennent constamment :
- Donnée manquante : la colonne
date_naissanced'un employé reste NULL tant que l'information n'est pas collectée. Insérer une date fictive fausserait les calculs d'âge. - Donnée inapplicable : la colonne
date_livraisonreste NULL tant que la commande n'est pas expédiée. Forcer une valeur par défaut ici génère des erreurs métier difficiles à détecter. - Champ optionnel non renseigné :
telephone_secondaireousite_webpeuvent légitimement rester NULL sans compromettre l'enregistrement.
Modéliser les NULL dès la conception évite les valeurs sentinelles comme -1 ou « N/A », qui polluent les requêtes et masquent les vraies absences.
Syntaxe des opérateurs NULL en SQL
Deux opérateurs standards testent la nullité, disponibles sur MySQL, PostgreSQL, SQL Server, Oracle et SQLite :
- IS NULL : retourne TRUE si la valeur est absente
- IS NOT NULL : retourne TRUE si la colonne contient une vraie valeur
L'opérateur = ne fonctionne pas avec NULL — jamais.
Exemple 1 : filtrer avec IS NULL et IS NOT NULL
-- Employés dont la date de naissance n'est pas encore saisie SELECT id, nom, prenom FROM employes WHERE date_naissance IS NULL; -- Produits dont le prix est renseigné SELECT id, libelle, prix FROM produits WHERE prix IS NOT NULL;
Les pièges courants avec NULL
Piège 1 : comparer directement avec NULL ne retourne rien
La requête ci-dessous ne retourne aucune ligne, même si des NULL existent dans la colonne — = NULL produit toujours UNKNOWN.
-- Incorrect : "date_naissance = NULL" est toujours UNKNOWN, jamais TRUE SELECT * FROM employes WHERE date_naissance = NULL; -- Correct : IS NULL teste l'absence de valeur SELECT * FROM employes WHERE date_naissance IS NULL;
Piège 2 : NULL se propage dans les calculs
Toute opération arithmétique avec NULL retourne NULL. salaire + prime quand prime est NULL donne NULL, pas le salaire seul. Ce comportement fausse totaux, moyennes et calculs de paie si on ne l'anticipe pas.
-- NULL contamine toute expression arithmétique SELECT 1 + NULL; -- Retourne : NULL SELECT 100 * NULL; -- Retourne : NULL SELECT NULL / 5; -- Retourne : NULL -- Si prime est NULL, le total vaut NULL, pas le salaire seul SELECT nom, salaire + NULL AS salaire_total FROM employes;
Piège 3 : les fonctions d'agrégation ignorent les NULL (sauf COUNT(*))
SUM, AVG, MAX, MIN et COUNT(colonne) sautent les lignes NULL sans prévenir. COUNT(*) est la seule exception — il compte toutes les lignes, y compris celles avec des NULL. Un AVG(prime) peut donc sembler élevé simplement parce qu'il exclut les employés sans prime.
-- COUNT(*) : toutes les lignes, NULL inclus SELECT COUNT(*) FROM employes; -- COUNT(colonne) : seulement les lignes non NULL SELECT COUNT(date_naissance) FROM employes; -- AVG saute les NULL : moyenne calculée sur les lignes renseignées uniquement SELECT AVG(prime) FROM employes; -- Pour traiter les NULL comme 0 dans la moyenne, utiliser COALESCE SELECT AVG(COALESCE(prime, 0)) FROM employes;
Remplacer NULL par une valeur par défaut : COALESCE et IFNULL
COALESCE prend plusieurs arguments et retourne le premier qui n'est pas NULL. C'est la version portable — valable sur tous les SGBD. IFNULL() existe en MySQL et NVL() en Oracle, mais COALESCE fonctionne partout.
-- Si prime est NULL, on substitue 0 pour que le calcul reste cohérent SELECT nom, salaire + COALESCE(prime, 0) AS salaire_total FROM employes; -- Cascade de substitutions : mobile d'abord, fixe ensuite, texte par défaut SELECT COALESCE(telephone_mobile, telephone_fixe, 'Non renseigné') AS contact FROM clients; -- IFNULL (MySQL uniquement) : équivalent de COALESCE à deux arguments SELECT IFNULL(commentaire, 'Aucun commentaire') FROM commandes; -- NVL (Oracle uniquement) SELECT NVL(bonus, 0) FROM employes;
NULL dans les JOIN
Un LEFT JOIN produit des NULL dans les colonnes de la table de droite pour toutes les lignes sans correspondance. C'est ce comportement qui permet d'identifier des absences : clients sans commande, produits jamais vendus, employés sans projet assigné.
-- Clients sans commande : après un LEFT JOIN, l'absence se lit dans le NULL
SELECT c.nom, c.prenom
FROM clients c
LEFT JOIN commandes co ON c.id = co.client_id
WHERE co.id IS NULL;Contrainte NOT NULL : bloquer les NULL à la source
La solution la plus fiable reste d'interdire NULL là où il n'a rien à faire. La contrainte NOT NULL dans le DDL garantit qu'une colonne critique aura toujours une valeur.
-- Colonnes obligatoires : NOT NULL interdit l'insertion sans valeur CREATE TABLE employes ( id INT NOT NULL AUTO_INCREMENT, nom VARCHAR(100) NOT NULL, prenom VARCHAR(100) NOT NULL, email VARCHAR(200) NOT NULL, date_naissance DATE, -- Optionnel prime DECIMAL(10,2), -- NULL si pas de prime PRIMARY KEY (id) );
Conclusion
NULL n'est pas compliqué — il est juste différent de ce qu'on attend. Une fois qu'on accepte que NULL signifie « absence », que = NULL ne fonctionne pas, et que les calculs avec NULL produisent NULL, la plupart des comportements inattendus deviennent prévisibles. Utilisez IS NULL / IS NOT NULL pour filtrer, COALESCE pour substituer, et NOT NULL dans vos schémas pour les colonnes qui n'ont pas à être vides.
Par carabde | Mis à jour le 29 avril 2026