Question 1Que renvoie SELECT * FROM customer WHERE email = NULL; ?
WHERE en profondeur ③ — IS NULL et IN pour le filtrage NULL et ensembliste
Le troisième article approfondi sur WHERE — filtrage sur NULL et sur ensembles. Couvre la logique à trois valeurs, IS NULL / IS NOT NULL, IN / NOT IN, et le piège NOT IN + NULL, le tout sur un jeu de données customer chargé depuis CSV.
Les données qu'on va utiliser — la table customer (avec des NULL)
Le troisième article approfondi sur WHERE couvre NULL et le filtrage ensembliste. On va travailler avec une table customer (8 lignes) chargée depuis CSV, où les colonnes age / email / country ont chacune des lignes avec NULL (valeur inconnue). Dans les tables du monde réel, c'est normal pour les colonnes non obligatoires de mélanger des NULL — « email non enregistré », « pays laissé vide », et ainsi de suite.
Les cinq exercices de cet article parcourent dans l'ordre : la bonne façon de récupérer les NULL (IS NULL / IS NOT NULL), la correspondance avec une liste de candidats (IN / NOT IN), et enfin le piège facile à manquer quand on utilise NOT IN sur des données qui contiennent des NULL.
NULL et logique à trois valeurs — true, false, unknown
Dans la plupart des langages de programmation, une condition vaut soit TRUE soit FALSE — deux choix. SQL ajoute un état de plus : NULL (inconnu). Ça s'appelle la logique à trois valeurs. NULL ne veut pas dire « la valeur est vide » ; ça veut dire « la valeur n'est pas connue ». Même NULL = NULL s'évalue à NULL (inconnu) — comparer deux inconnus laisse le résultat inconnu.
WHERE condition ne garde que les lignes où la condition est TRUE. Les lignes NULL et FALSE sont toutes les deux exclues. Une fois cette règle assimilée, tu verras pourquoi WHERE email = NULL revient toujours vide.
Pourquoi `email = NULL` ne renvoie rien
La comparaison email = NULL renvoie toujours NULL (inconnu) quand l'un des côtés est NULL. 'unknown' = NULL et NULL = NULL s'évaluent tous les deux à NULL. WHERE ne garde que les lignes où la condition est TRUE, donc les conditions NULL sont exclues, laissant 0 ligne.
Pour récupérer les NULL, il te faut la syntaxe dédiée colonne IS NULL / colonne IS NOT NULL. Elles ne font pas de comparaison d'égalité — elles vérifient directement si la valeur est NULL — et le résultat est toujours TRUE ou FALSE.
« Zéro client n'a churné » ?
Quand j'extrayais « le compte des clients qui n'ont pas churné (deleted_at IS NULL) », j'ai un jour écrit SELECT COUNT(*) FROM user WHERE deleted_at = NULL; et le résultat est revenu à 0.
En réalité il y avait des milliers d'utilisateurs actifs, mais deleted_at = NULL s'évalue toujours à NULL (inconnu) et est exclu par WHERE, donc peu importe combien d'utilisateurs existaient, le résultat était toujours 0. C'est une erreur facile quand tu débutes en SQL — prends l'habitude d'utiliser `IS NULL` / `IS NOT NULL` pour chaque vérification de NULL.
IS NULL et IS NOT NULL — récupérer les valeurs inconnues
Pour récupérer les lignes où une valeur est NULL (inconnue), utilise `colonne IS NULL`. Pour récupérer les lignes qui ne sont pas NULL, utilise colonne IS NOT NULL. Souviens-toi juste de ne jamais utiliser `= NULL` ni `<> NULL` et tu esquives le piège de la logique à trois valeurs.
Comme le code ci-dessous le montre, la syntaxe est juste IS au lieu de = — mais le résultat est complètement différent. = NULL ne renvoie rien ; IS NULL renvoie correctement les lignes NULL.
-- 1) NG : = NULL ne récupère rien (toujours NULL = exclu)
SELECT name, email FROM customer WHERE email = NULL;
-- Résultat : 0 ligne
-- 2) OK : IS NULL récupère les lignes NULL
SELECT name, email FROM customer WHERE email IS NULL;
-- Résultat : 4 lignes (Bob / Dave / Frank / Henry)
-- 3) Récupère les lignes non-NULL
SELECT name, email FROM customer WHERE email IS NOT NULL;
-- Résultat : 4 lignes (Alice / Carol / Eve / Grace)
IN et NOT IN — correspondance avec une liste de candidats
Quand tu veux tester si la valeur d'une colonne est dans une liste de candidats — « country est Japan, US ou UK » — c'est IN. Écrire colonne IN (valeur1, valeur2, ...) renvoie les lignes où la colonne correspond à n'importe lequel des candidats. Ça veut dire la même chose que colonne = valeur1 OR colonne = valeur2 OR colonne = valeur3 ; on choisit souvent IN juste pour la lisibilité.
Ajouter NOT IN renvoie les lignes qui ne correspondent à aucun candidat.
-- 1) IN : correspond à n'importe quel candidat
SELECT name, country FROM customer
WHERE country IN ('Japan', 'US');
-- Même sens, écrit avec OR
SELECT name, country FROM customer
WHERE country = 'Japan' OR country = 'US';
-- 2) NOT IN : ne correspond à aucun des candidats
SELECT name, country FROM customer
WHERE country NOT IN ('Japan');
Le piège `NOT IN` + NULL
NOT IN ('Japan') a l'air de récupérer « les clients dont le country n'est pas Japan », mais il exclut aussi les lignes où `country` est NULL. C'est parce que country NOT IN ('Japan') s'évalue en interne comme country <> 'Japan' (pas égal), et NULL <> 'Japan' renvoie NULL (inconnu). NULL n'est pas TRUE, donc WHERE éjecte la ligne.
En poussant plus loin, écrire NOT IN ('Japan', NULL) — avec un NULL dans la liste de candidats — fait que chaque ligne s'évalue à NULL et disparaît. Quand tu utilises NOT IN sur une colonne qui peut contenir NULL, rends toujours la gestion de NULL explicite (colonne NOT IN (...) AND colonne IS NOT NULL) ou réécris la requête en termes de IN.
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Laquelle des descriptions suivantes décrit correctement le filtrage avec IN ?
Question 3En lançant WHERE country NOT IN ('Japan') sur une table customer où la colonne country contient des NULL, comment les lignes country-NULL sont-elles gérées ?