Pourquoi NOT IN avec un ensemble contenant NULL renvoie toujours FALSE / NULL?

21

J'avais une requête (pour Postgres et Informix) avec une NOT INclause contenant une sous-requête qui, dans certains cas, renvoyait des NULLvaleurs, ce qui faisait que cette clause (et la requête entière) ne retournait rien.

Quelle est la meilleure façon de comprendre cela? Je pensais NULLà quelque chose sans valeur, et je ne m'attendais donc pas à ce que la requête échoue, mais ce n'est évidemment pas la bonne façon de penser NULL.

newenglander
la source

Réponses:

29

Logique booléenne - ou logique à trois valeurs

  • IN est un raccourci pour une série de conditions OR
  • x NOT IN (1, 2, NULL) est le même que NOT (x = 1 OR x = 2 OR x = NULL)
  • ... est le même que x <> 1 AND x <> 2 AND x <> NULL
  • ... est identique à true AND true AND unknown**
  • ... = unknown**
  • ... ce qui est presque le même que falsedans ce cas car il ne remplira pas la WHEREcondition **

Maintenant, c'est pourquoi les gens utilisent EXISTS+ NOT EXISTSplutôt que IN+ NOT IN. Voir également L'utilisation de la logique NOT en relation avec les index pour plus d'informations.

** Remarque: unknownest le même qu'à falsela fin d'une expression dans une WHEREcondition.
Pendant que l'expression est en cours d'évaluation, alors on ne sait pas
Voir le commentaire de @ kgrittn ci-dessous pour savoir pourquoi

gbn
la source
10
Même avec la clarification, c'est techniquement faux, et d'une manière qui pourrait brûler quelqu'un. Par exemple, si vous considérez x <> NULLcomme résolvant à FALSE, vous vous attendez NOT (x <> NULL)à évaluer TRUEet ce n'est pas le cas. Les deux évaluent UNKNOWN. L'astuce est qu'une ligne n'est sélectionnée que si la WHEREclause (si présente) est évaluée à TRUE- une ligne est omise si la clause est évaluée à FALSEou UNKNOWN. Ce comportement (en général, et pour le NOT INprédicat en particulier) est rendu obligatoire par la norme SQL.
kgrittn
Aussi NULL NOT IN (some_subquery)ne devrait pas retourner la ligne extérieure , sauf si some_subqueryne renvoie pas de lignes. C'est pourquoi le plan d'exécution lorsque les deux colonnes sont Null-able peut être considérablement plus cher. Exemple SQL Server
Martin Smith