D'expérience, beaucoup d'erreurs inattendues dans les bibliothèques, outils et langages sont liées à la présence de valeurs manquantes.

Par exemple, considère un array NumPy 1D contenant des valeurs NaN.

Code Python : array NumPy 1D contenant des valeurs NaN

Quand on agrège cet array NumPy pour calculer, disons, sa somme, on obtient le résultat suivant :

Code Python : somme d'un array NumPy contenant des NaN, résultat NaN

Étrange, non ?

Alors qu'un résultat de 6 aurait eu plus de sens ici, NumPy produit une valeur NaN à la place.

Bref, ce n'est pas le sujet du jour, mais tu vois l'idée.

Une erreur silencieuse similaire existe aussi en SQL, plus précisément dans l'utilisation de la clause NOT IN, et beaucoup d'utilisateurs SQL ne la connaissent pas.

Voyons ça !

Imaginons qu'on a les tables suivantes (students et names) dans notre base de données :

Tables students et names de l'exemple SQL sur la clause NOT IN

L'objectif est de sélectionner les enregistrements de la table students où first_name n'est pas dans la table names.

Une façon de faire est d'utiliser la clause NOT IN, comme ci-dessous :

Code SQL : requête avec NOT IN sélectionnant les étudiants absents de la table names

Et on obtient bien les résultats attendus.

Tout va bien jusque-là !

Maintenant, supposons que notre table names contienne une valeur NULL :

Table names avec une valeur NULL ajoutée, exemple SQL de la clause NOT IN

Si on relance la même requête, on n'obtient aucun résultat cette fois :

Code SQL : requête NOT IN ne retournant aucun résultat à cause de la valeur NULL

Petite parenthèse : si on avait utilisé la clause IN pour sélectionner les lignes de la table students où first_name est dans la table names, on constate que ça fonctionne comme prévu :

Code SQL : requête avec la clause IN fonctionnant comme prévu malgré la valeur NULL

C'est étrange, non ?

Pourquoi n'obtient-on aucun résultat avec NOT IN ?

La raison pour laquelle NOT IN ne retourne aucun résultat alors que IN fonctionne comme prévu tient au fonctionnement interne de ces deux clauses.

Pour simplifier, imaginons qu'on vérifie le premier enregistrement (où first_name est "John") de la table students :

Vérification du prénom John de la table students parmi les valeurs de la table names

La clause WHERE a besoin d'une valeur booléenne pour déterminer si un enregistrement doit être retenu ou non.

Quand on utilise IN, cette valeur booléenne est évaluée avec l'opérateur OR comme suit :

Expression booléenne : clause IN évaluée avec l'opérateur OR sur chaque valeur de names

Si n'importe quelle condition est TRUE, la ligne est retenue.

En revanche, quand on utilise NOT IN, la valeur booléenne est évaluée avec l'opérateur AND comme suit :

Expression booléenne : clause NOT IN évaluée avec l'opérateur AND sur chaque valeur de names

Pour que cette expression soit TRUE, toutes les conditions individuelles DOIVENT être TRUE.

Mais la condition (JOHN != None) pose problème car, en règle générale, elle produit une valeur UNKNOWN.

L'expression entière s'évalue donc à UNKNOWN, et aucun enregistrement n'est retourné.

C'est le cas pour chaque enregistrement de la table students. Résultat : la requête ne retourne aucun enregistrement :

Code SQL : requête NOT IN ne retournant aucun résultat à cause de la valeur NULL

Que faire à la place ?

Il existe plusieurs façons d'éviter ça.

Puisque notre objectif est de sélectionner les enregistrements de la table students où first_name n'est pas dans la table names, on peut :

  • Filtrer les valeurs NULL dans la sous-requête :

Code SQL : requête NOT IN avec filtre des valeurs NULL dans la sous-requête
  • Utiliser un Anti Join : un anti join retourne uniquement les lignes de la table de gauche qui n'ont aucune correspondance dans la table de droite. C'est exactement ce qu'il nous faut ici, et voici comment l'implémenter :

Code SQL : anti join retournant les étudiants sans correspondance dans la table names

Ce genre d'erreurs peut parfois prendre un temps considérable à débugger si tu n'en as pas conscience au préalable.

J'espère que ça t'a été utile !

Si tu veux expérimenter avec ce qu'on a vu sur la clause NOT IN aujourd'hui, télécharge ce Jupyter Notebook : Notebook Clause NOT IN.

Envie d'aller plus loin ? DataXp t'attend : formations et parcours pour progresser en data science, machine learning et IA.

👉 À toi : peux-tu proposer une autre solution au problème ci-dessus ?


Commentaires

Avatar

ou participer

À lire ensuite

Des shots dans la même veine, à lire entre deux tâches.

Voir tous les shots
caret-right