Pourquoi NULL = NULL est-il évalué à false dans SQL Server

147

Dans le serveur SQL, si vous avez nullParam=NULLune clause where, la valeur est toujours false. Ceci est contre-intuitif et m'a causé de nombreuses erreurs. Je comprends que les mots clés IS NULLet IS NOT NULLsont la bonne façon de procéder. Mais pourquoi le serveur SQL se comporte-t-il de cette façon?

Byron Whitlock
la source
166
Je n'ai pas de sœur et mon amie non plus. Si "NULL = NULL" alors nous avons une sœur commune, et nous sommes donc liés! :)
Matt Hamilton
11
Il existe une controverse de longue date sur les NULL SQL (voir par exemple: en.wikipedia.org/wiki/Null_%28SQL%29#Controversy et firstsql.com/inulls.htm ). Le point spécifique ici est que l'égalité est un concept mathématique établi de longue date et SQL le viole - l'égalité est réflexive: pour chaque x, x = x. Cela doit toujours être vrai, sinon on introduit une interprétation de l'égalité qui n'est pas standard et la confusion est le résultat évident.
MaD70
14
Cela ne viole pas du tout les mathématiques. Je pense à deux chiffres. Je ne vais pas vous dire ce qu'ils sont cependant. Alors maintenant tu me dis, sont-ils égaux?
Tom H
10
@Matt, je ne suis pas d'accord avec votre analogie. NULL = NULL ne signifierait pas que vous avez une sœur commune, cela signifierait que vous n'avez pas de sœur tous les deux.
reustmd le
5
@ manu08 Non, l'implémentation actuelle (que NULL n'est jamais égal à NULL) signifie que nous manquons tous les deux d'une sœur, ce qui était mon point.
Matt Hamilton

Réponses:

206

Considérez le nul comme "inconnu" dans ce cas (ou "n'existe pas"). Dans l'un ou l'autre de ces cas, vous ne pouvez pas dire qu'ils sont égaux, car vous ne connaissez pas la valeur de l'un ou l'autre. Ainsi, null = null est évalué comme non vrai (faux ou nul, selon votre système), car vous ne connaissez pas les valeurs pour dire qu'elles SONT égales. Ce comportement est défini dans la norme ANSI SQL-92.

EDIT: Cela dépend de votre paramètre ansi_nulls . si vous avez ANSI_NULLS désactivé, cela évaluera à vrai. Exécutez le code suivant pour un exemple ...

set ansi_nulls off

if null = null
    print 'true'
else
    print 'false'


set ansi_nulls ON

if null = null
    print 'true'
else
    print 'false'
Scott Ivey
la source
11
x = x n'est vrai que lorsque x est une valeur connue . NULL est une représentation textuelle d'une valeur inconnue . Si vous avez deux valeurs inconnues, vous ne pouvez rien affirmer de manière concluante sur leur égalité. Je pense que cela est également vrai depuis quelques siècles.
Dewayne Christensen
4
Puisque nous sommes en décembre, utilisons un exemple saisonnier. J'ai deux cadeaux sous l'arbre. Maintenant, dites-moi si j'en ai deux de la même chose ou non.
Dewayne Christensen
5
SQL NULL n'est pas différent du NaN à virgule flottante IEEE, où vous avez également (NaN == NaN) == false && (NaN != Nan) == false && (NaN < NaN) == false && ...- parce que, eh bien, si ce n'est pas un nombre, vous ne pouvez tout simplement pas en dire beaucoup; c'est quelque chose d'inconnu. Le concept est solide, même s'il n'est pas intuitif pour les personnes qui ne l'ont jamais vu auparavant.
Pavel Minaev
8
Il n'y a pas de violation de la réflexivité ici, car NULL n'est pas membre de l'ensemble de valeurs (domaine, en termes relationnels). NULL n'est pas une valeur . C'est un espace réservé pour la valeur qui est inconnue.
Pavel Minaev
9
Pour le dire en d'autres termes, chaque NULLexpression SQL peut être traitée comme une variable mathématique distincte . Une expression NULL = NULLdoit donc être traitée comme x = y, où xet ysont des variables indépendantes. Maintenant, si quelqu'un vous demande, quelle est la valeur de x = y? La seule réponse raisonnable est «certains z». Nous avons donc (x = y) = z- ou, transcrivant retour à SQL, (NULL = NULL) = NULL.
Pavel Minaev
131

Quel âge a Frank? Je ne sais pas (nul).

Quel âge a Shirley? Je ne sais pas (nul).

Frank et Shirley ont-ils le même âge?

La bonne réponse devrait être "Je ne sais pas" (nul), pas "non", car Frank et Shirley ont peut- être le même âge, nous ne le savons tout simplement pas.

Neil McGuigan
la source
4
Je ne suis pas d'accord pour dire que nul signifie «inconnu». Ce que cela signifie en fait, c'est "pas de données". Cela pourrait être utilisé pour représenter le cas où l'information n'est pas connue, mais il est en fait plus susceptible d'être utilisé pour indiquer que quelque chose n'existe pas. Pour continuer votre exemple: quel est le deuxième prénom de Frank? Il n'en a pas (nul). Quel est le deuxième prénom de Shirley? Elle n'en a pas (nul). Frank et Shirley ont-ils le même deuxième prénom? Oui? Non? Je ne sais pas? Je peux voir un argument pour «non», et je peux voir un argument pour «ne sais pas», mais il n'y a pas de véritable argument pour «oui» à moins que vous soyez trop littéral.
Richiban
2
@richiban Je ne suis pas d'accord. L'absence d'une ligne signifie `` pas de données ''
Neil McGuigan
1
@NeilMcGuigan C'est vrai si pour les données qui ont leur propre table, mais qu'en est-il des données représentées dans une colonne? N'utiliseriez-vous pas «null» pour représenter le fait que les données n'existent pas? «Inconnu» est une raison très spécifique pour laquelle les données sont absentes.
Richiban
3
Mais null = nullcède FALSE, non NULL.
slartidan
1
@slartidan Je suis d'accord avec vous, mais c'est incorrect
Neil McGuigan
28

J'espère ici clarifier ma position.

Cette NULL = NULLévaluation FALSEest fausse. Hacker et Mister ont répondu correctement NULL. Voici pourquoi. Dewayne Christensen m'a écrit, dans un commentaire à Scott Ivey :

Puisque nous sommes en décembre, utilisons un exemple saisonnier. J'ai deux cadeaux sous l'arbre. Maintenant, dites-moi si j'en ai deux de la même chose ou non.

Ils peuvent être différents ou être égaux, vous ne le savez pas tant que l'on n'a pas ouvert les deux cadeaux. Qui sait? Vous avez invité deux personnes qui ne se connaissent pas et qui vous ont fait le même cadeau - rare, mais pas impossible § .

Alors la question: ces deux cadeaux INCONNU sont-ils identiques (égaux, =)? La bonne réponse est: INCONNU (c'est-à-dire NULL).

Cet exemple visait à démontrer que ".. ( falseou null, selon votre système) .." est une réponse correcte - ce n'est pas, seulement NULL est correcte en 3VL (ou est-ce que vous acceptez un système qui donne de mauvaises réponses? )

Une réponse correcte à cette question doit souligner ces deux points:

  • la logique à trois valeurs (3VL) est contre-intuitive (voir d'innombrables autres questions à ce sujet sur Stackoverflow et dans d'autres forums pour vous en assurer);
  • Souvent, les SGBD basés sur SQL ne respectent même pas 3VL, ils donnent parfois de mauvaises réponses (comme l'affirme l'affiche d'origine, SQL Server le fait dans ce cas).

Je répète donc: SQL ne sert à rien de forcer à interpréter la propriété réflexive de l'égalité, qui stipule que:

for any x, x = x §§ (en clair: quel que soit l'univers du discours, une «chose» est toujours égale à elle-même ).

.. dans un 3VL ( TRUE, FALSE, NULL). L'attente des personnes se conformerait à 2VL ( TRUE, FALSEqui même dans SQL est valable pour toutes les autres valeurs), à savoir x = x évaluer toujours TRUE , pour toute valeur possible de x - sans exception.

Notez également que les NULL sont des " non-valeurs valides" " (comme leurs apologistes le prétendent) que l'on peut attribuer comme valeurs d'attribut (??) dans le cadre des variables de relation. Ce sont donc des valeurs acceptables de chaque type (domaine), pas seulement du type d'expressions logiques.

Et c'était mon point :, NULLcomme valeur, est une "bête étrange". Sans euphémisme, je préfère dire: non - sens .

Je pense que cette formulation est beaucoup plus claire et moins discutable - désolé pour ma faible maîtrise de l'anglais.

C'est seulement l' un des problèmes de NULLs. Mieux vaut les éviter complètement, si possible.

§ nous sommes préoccupés par les valeurs ici, donc le fait que les deux présents soient toujours deux objets physiques différents ne constitue pas une objection valable; si vous n'êtes pas convaincu je suis désolé, ce n'est pas ici le lieu pour expliquer la différence entre la sémantique valeur et "objet" (l'algèbre relationnelle a une sémantique de valeur dès le début - voir le principe d'information de Codd; je pense que certains implémenteurs de SGBD SQL ne ne se soucie même pas d'une sémantique commune).

§§ à ma connaissance, c'est un axiome accepté (sous une forme ou une autre, mais toujours interprété dans un 2VL) depuis l'antiquité et cela précisément parce qu'il est si intuitif. 3VLs (est une famille de logiques en réalité) est un développement beaucoup plus récent (mais je ne sais pas quand a été développé pour la première fois).

Note latérale: si quelqu'un introduit des types de bas , d' unité et d' option comme tentatives de justifier les NULL SQL, je ne serai convaincu qu'après un examen assez détaillé qui montrera comment les implémentations SQL avec des NULL ont un système de type sonore et clarifiera, enfin, ce que sont vraiment les NULL (ces «valeurs pas tout à fait»).


Dans ce qui suit, je citerai quelques auteurs. Toute erreur ou omission est probablement la mienne et non celle des auteurs originaux.

Joe Celko sur les NULL SQL

Je vois Joe Celko souvent cité sur ce forum. Apparemment, c'est un auteur très respecté ici. Alors, je me suis dit: "qu'est-ce qu'il a écrit sur les NULL SQL? Comment explique-t-il les nombreux problèmes des NULL?". Un de mes amis a une version ebook du SQL de Joe Celko pour les smarties: programmation SQL avancée, 3e édition . Voyons voir.

Tout d'abord, la table des matières. Ce qui me frappe le plus, c'est le nombre de fois où NULL est mentionné et dans les contextes les plus variés:

3.4 Arithmétique et valeurs NULL 109
3.5 Conversion de valeurs vers et à partir de NULL 110
3.5.1 Fonction NULLIF () 110
6 NULL: données manquantes dans SQL 185
6.4 Comparaison de NULL 190
6.5 NULL et logique 190
6.5.1 NULLS dans les prédicats de sous-requête 191
6.5.2 Standard Solutions SQL 193
6.6 Mathématiques et NULL 193
6.7 Fonctions et NULL 193
6.8 NULL et langages hôtes 194
6.9 Conseils de conception pour les NULL 195
6.9.1 Éviter les NULL des programmes hôtes 197
6.10 Remarque sur les valeurs NULL multiples 198
10.1 Prédicat IS NULL 241
10.1. 1 Sources des NULL 242
...

etc. Cela me semble un "cas spécial méchant".

J'entrerai dans certains de ces cas avec des extraits de ce livre, en essayant de me limiter à l'essentiel, pour des raisons de copyright. Je pense que ces citations relèvent de la doctrine du «fair use» et qu'elles peuvent même inciter à acheter le livre - j'espère donc que personne ne se plaindra (sinon je devrai en supprimer la plupart, sinon la totalité). De plus, je m'abstiendrai de signaler des extraits de code pour la même raison. Désolé pour ça. Achetez le livre pour en savoir plus sur le raisonnement datailed.

Numéros de page entre parenthèses dans ce qui suit.

Contrainte NOT NULL (11)

La contrainte de colonne la plus importante est NOT NULL, qui interdit l'utilisation de NULL dans une colonne. Utilisez cette contrainte régulièrement et supprimez-la uniquement lorsque vous avez une bonne raison. Cela vous aidera à éviter les complications des valeurs NULL lorsque vous effectuez des requêtes sur les données.

Ce n'est pas une valeur ; c'est un marqueur qui tient une place où une valeur pourrait aller.

Encore une fois, cette "valeur mais pas tout à fait une valeur" absurde. Le reste me paraît tout à fait raisonnable.

(12)

En bref, les NULL provoquent de nombreuses fonctionnalités irrégulières dans SQL, dont nous parlerons plus tard. Votre meilleur pari est simplement de mémoriser les situations et les règles pour les NULL lorsque vous ne pouvez pas les éviter.

À propos de SQL, NULL et infini:

(104) CHAPITRE 3: DONNÉES NUMÉRIQUES EN SQL

SQL n'a pas accepté le modèle IEEE pour les mathématiques pour plusieurs raisons.

...

Si les règles IEEE pour les mathématiques étaient autorisées dans SQL, nous aurions besoin de règles de conversion de type pour infini et d'un moyen de représenter une valeur numérique exacte infinie après la conversion. Les gens ont assez de problèmes avec les NULL, alors n'allons pas là-bas.

Les implémentations SQL sont indécises sur ce que signifie vraiment NULL dans des contextes particuliers:

3.6.2 Fonctions exponentielles (116)

Le problème est que les logarithmes ne sont pas définis lorsque (x <= 0). Certaines implémentations SQL renvoient un message d'erreur, certaines renvoient un NULL et DB2 / 400; la version 3 version 1 a renvoyé * NEGINF (abréviation de «infini négatif») comme résultat.

Joe Celko citant David McGoveran et CJ Date:

6 NULL: données manquantes dans SQL (185)

Dans leur livre A Guide to Sybase and SQL Server , David McGoveran et CJ Date ont déclaré: «C'est l'opinion de cet auteur que les NULL, du moins tels qu'ils sont actuellement définis et implémentés dans SQL, sont bien plus problématiques qu'ils ne valent et doivent être évités; ils affichent un comportement très étrange et incohérent et peuvent être une riche source d'erreur et de confusion. (Veuillez noter que ces commentaires et critiques s'appliquent à tout système prenant en charge les valeurs NULL de style SQL, et pas uniquement à SQL Server en particulier.) »

NULL en tant que toxicomanie :

(186/187)

Dans la suite de ce livre, je vous exhorte à ne pas les utiliser , ce qui peut sembler contradictoire, mais ce n'est pas le cas. Considérez un NULL comme un médicament; utilisez-le correctement et cela fonctionne pour vous, mais abusez-en et cela peut tout gâcher. Votre meilleure politique est d'éviter les valeurs NULL lorsque vous le pouvez et de les utiliser correctement lorsque vous le devez.

Mon unique objection ici est de «les utiliser correctement», ce qui interagit mal avec des comportements d'implémentation spécifiques.

6.5.1 NULLS dans les prédicats de sous-requête (191/192)

Les gens oublient qu'une sous-requête cache souvent une comparaison avec un NULL. Considérez ces deux tableaux:

...

Le résultat sera vide. C'est contre - intuitif , mais correct.

(séparateur)

6.5.2 Solutions SQL standard (193)

SQL-92 a résolu certains des problèmes 3VL (logique à trois valeurs) en ajoutant un nouveau prédicat de la forme:

<condition de recherche> IS [NOT] TRUE | FALSE | INCONNUE

Mais INCONNU est une source de problèmes en soi, de sorte que CJ Date, dans son livre cité ci-dessous, recommande au chapitre 4.5. Éviter les valeurs nulles dans SQL :

  • N'utilisez le mot-clé INCONNU dans aucun contexte.

Lisez "ASIDE" sur INCONNU, également lié ci-dessous.

6.8 NULL et langues hôtes (194)

Cependant, vous devez savoir comment les NULL sont gérés lorsqu'ils doivent être passés à un programme hôte. Aucun langage hôte standard pour lequel une intégration est définie ne prend en charge les valeurs NULL, ce qui est une autre bonne raison d'éviter de les utiliser dans votre schéma de base de données.

(séparateur)

6.9 Conseils de conception pour les NULL (195)

C'est une bonne idée de déclarer toutes vos tables de base avec des contraintes NOT NULL sur toutes les colonnes chaque fois que possible. Les NULL confondent les personnes qui ne connaissent pas SQL, et les NULL sont chers.

Objection: NULL confond même les personnes qui connaissent bien SQL, voir ci-dessous.

(195)

Les valeurs NULL doivent être évitées dans les FOREIGN KEY. SQL autorise cette relation «bénéfice du doute», mais il peut entraîner une perte d'informations dans les requêtes impliquant des jointures. Par exemple, étant donné un code de numéro de pièce dans l'inventaire qui est référencé comme une clé étrangère par une table Commandes, vous aurez des problèmes pour obtenir une liste des pièces qui ont un NULL. C'est une relation obligatoire; vous ne pouvez pas commander une pièce qui n'existe pas.

(séparateur)

6.9.1 Éviter les valeurs NULL des programmes hôtes (197)

Vous pouvez éviter de mettre des valeurs NULL dans la base de données à partir des programmes hôtes avec une certaine discipline de programmation.

...

  1. Déterminez l'impact des données manquantes sur la programmation et la création de rapports: les colonnes numériques avec NULL posent problème, car les requêtes utilisant des fonctions d'agrégation peuvent fournir des résultats trompeurs.

(séparateur)

(227)

La somme () d'un ensemble vide est toujours NULL. L'une des erreurs de programmation les plus courantes lors de l'utilisation de cette astuce est d'écrire une requête qui pourrait renvoyer plus d'une ligne. Si vous n'y avez pas réfléchi, vous avez peut-être écrit le dernier exemple comme suit: ...

(séparateur)

10.1.1 Sources des NULL (242)

Il est important de se rappeler où les NULL peuvent se produire. Ils sont plus qu'une simple valeur possible dans une colonne . Les fonctions d'agrégation sur des ensembles vides, les jointures externes, les expressions arithmétiques avec des valeurs NULL et les opérateurs OLAP renvoient toutes des valeurs NULL. Ces constructions apparaissent souvent sous forme de colonnes dans les vues.

(séparateur)

(301)

Un autre problème avec les valeurs NULL est détecté lorsque vous essayez de convertir des prédicats IN en prédicats EXISTS.

(séparateur)

16.3 Fonctions de prédicat ALL et Extrema (313)

Il est au début contre-intuitif que ces deux prédicats ne soient pas les mêmes en SQL:

...

Mais vous devez vous rappeler les règles des fonctions extrema - elles suppriment toutes les valeurs NULL avant de renvoyer les valeurs supérieures ou inférieures. Le prédicat ALL ne supprime pas les NULL, vous pouvez donc les obtenir dans les résultats.

(séparateur)

(315)

Cependant, la définition de la norme est rédigée par la négative, de sorte que les NULL bénéficient du doute. ...

Comme vous pouvez le voir, il est judicieux d'éviter les valeurs NULL dans les contraintes UNIQUE.

Discussion GROUPE BY:

Les NULL sont traités comme s'ils étaient tous égaux les uns aux autres et forment leur propre groupe. Chaque groupe est ensuite réduit à une seule ligne dans une nouvelle table de résultats qui remplace l'ancienne.

Cela signifie que pour GROUP BY, la clause NULL = NULL ne s'évalue pas à NULL, comme dans 3VL, mais à TRUE.

Le standard SQL est déroutant:

ORDER BY et NULL (329)

La question de savoir si une valeur de clé de tri qui est NULL est considérée comme supérieure ou inférieure à une valeur non NULL est définie par l'implémentation, mais ...

... Il existe des produits SQL qui le font dans les deux cas.

En mars 1999, Chris Farrar a soulevé une question d'un de ses développeurs qui l'a amené à examiner une partie du standard SQL que je croyais comprendre . Chris a trouvé quelques différences entre la compréhension générale et le libellé réel de la spécification .

Etc. Je pense que c'est assez par Celko.

Date CJ sur les NULL SQL

CJ Date est plus radical sur les NULL: évitez les NULL en SQL, point final. En fait, le chapitre 4 de sa théorie SQL et relationnelle: Comment écrire du code SQL précis est intitulé "PAS DE DUPLICATES, PAS DE NULLS", avec des sous-chapitres "4.4 Qu'est-ce qui ne va pas avec les Nulls?" et "4.5 Eviter les Nulls en SQL" (suivez le lien: grâce à Google Livres, vous pouvez lire certaines pages en ligne).

Fabian Pascal sur les NULL SQL

De ses problèmes pratiques dans la gestion de base de données - Une référence pour le praticien de la pensée (pas d'extraits en ligne, désolé):

10.3 Implications pratiques

10.3.1 NULL SQL

... SQL souffre des problèmes inhérents à 3VL ainsi que de nombreuses bizarreries, complications, contre-intuitivité et erreurs flagrantes [10, 11]; parmi eux sont les suivants:

  • Les fonctions d'agrégation (par exemple, SUM (), AVG ()) ignorent les valeurs NULL (à l'exception de COUNT ()).
  • Une expression scalaire sur une table sans lignes est évaluée de manière incorrecte à NULL, au lieu de 0.
  • L'expression "NULL = NULL" est évaluée à NULL, mais n'est en fait pas valide en SQL; pourtant ORDER BY traite les NULL comme égaux (tout ce qu'ils précèdent ou suivent les valeurs «régulières» est laissé au fournisseur de SGBD).
  • L'expression "x IS NOT NULL" n'est pas égale à "NOT (x IS NULL)", comme c'est le cas dans 2VL.

...

Tous les dialectes SQL mis en œuvre commercialement suivent cette approche 3VL et, par conséquent, non seulement ils présentent ces problèmes, mais ils ont également des problèmes d'implémentation spécifiques, qui varient d'un produit à l'autre .

MaD70
la source
4
"Et c'était mon point: NULL, en tant que valeur, est une" bête étrange "." - c'est parce que ce NULLn'est pas une valeur.
Pavel Minaev
1
En outre, SQL Server ne donne pas (NULL = NULL) -> FALSE. Pour citer la documentation pour ANSI_NULLS: "Lorsque ON est spécifié, toutes les comparaisons à une valeur nulle sont évaluées à INCONNU . Lorsque OFF est spécifié, les comparaisons de valeurs non UNICODE à une valeur nulle sont évaluées à TRUE si les deux valeurs sont NULL."
Pavel Minaev
@ Pavel Minaev: a) et en quoi VRAI vaut-il mieux que FAUX? b) Si ce n'est pas une valeur, pourquoi est-elle affectée comme partie des valeurs de variable?
MaD70
1
>> Puisque nous sommes en décembre, utilisons un exemple saisonnier. J'ai deux cadeaux sous l'arbre. Maintenant, dites-moi si j'en ai deux de la même chose ou non. ..... oui, vous l'avez fait dans la mesure où vous avez deux choses et en ce qui vous concerne en ce moment , dans la mesure de vos connaissances actuelles, elles sont exactement les mêmes pour vous
Brad Thomas
3
null = null doit être vrai. null est une valeur bien définie qui peut représenter une valeur inconnue , mais elle peut également représenter l' absence d'une valeur. Ce devrait être au développeur de décider ce que représente null, mais null lui-même est absolument une valeur et null est null = null. Toute autre implémentation est vouée au désastre, car vous introduisez une logique ternaire dans des prédicats qui sont fondamentalement booléens. Je suis APPELÉ que cela devienne un paramètre permanent sur le serveur SQL. OFF OFF OFF avec elle.
Triynko
9

Cela dépend peut-être, mais je pensais que les NULL=NULLévaluations NULLressemblaient à la plupart des opérations avec NULL comme opérande.

Michael Krelin - hacker
la source
9

Ce n'est pas parce que vous ne savez pas ce que sont deux choses. Si quand vous pensez à NULL"NULL" (chaîne), vous voulez probablement un test d'égalité différent comme le IS DISTINCT FROMAND de PostgresqlIS NOT DISTINCT FROM

Extrait de la documentation PostgreSQL sur «Fonctions et opérateurs de comparaison»

expression d' IS DISTINCT FROMexpression

expression d' IS NOT DISTINCT FROMexpression

Pour les entrées non nulles, IS DISTINCT FROMest identique à l' <>opérateur. Cependant, si les deux entrées sont nulles, elle renvoie false, et si une seule entrée est nulle, elle renvoie true. De même, IS NOT DISTINCT FROMest identique à =pour les entrées non nulles, mais il renvoie true lorsque les deux entrées sont nulles et false lorsqu'une seule entrée est nulle. Ainsi, ces constructions agissent effectivement comme si null était une valeur de données normale, plutôt que «inconnue».

Evan Carroll
la source
5

Le concept de NULL est pour le moins discutable. Codd a introduit le modèle relationnel et le concept de NULL en contexte (et a continué en proposant plus d'un type de NULL!) Cependant, la théorie relationnelle a évolué depuis les écrits originaux de Codd: certaines de ses propositions ont depuis été abandonnées (par exemple, la clé primaire) et d'autres n'ont jamais été pris en compte (par exemple les opérateurs theta). Dans la théorie relationnelle moderne (véritable théorie relationnelle, je dois souligner) NULL n'existe tout simplement pas. Voir le troisième manifeste.http://www.thethirdmanifesto.com/

Le langage SQL souffre du problème de la rétrocompatibilité. NULL a trouvé son chemin dans SQL et nous sommes coincés avec lui. On peut soutenir que l'implémentation de NULLSQL est imparfaite (l'implémentation de SQL Server rend les choses encore plus compliquées en raison de son ANSI_NULLSoption).

Je recommande d'éviter l'utilisation de colonnes NULLable dans les tables de base.


Même si je ne devrais peut-être pas être tenté, je voulais juste apporter ma propre correction sur la façon dont NULL fonctionnement de SQL:

NULL= NULLévalue àUNKNOWN .

UNKNOWN est une valeur logique.

NULL est une valeur de données.

C'est facile à prouver, par exemple

SELECT NULL = NULL

génère correctement une erreur dans SQL Server. Si le résultat était une valeur de données, nous nous attendrions à voirNULL , comme certaines réponses ici (à tort) suggèrent que nous le ferions.

La valeur logique UNKNOWN est traitée différemment dans SQL DML et SQL DDL respectivement.

Dans SQL DML, UNKNOWN lignes sont supprimées du jeu de résultats.

Par exemple:

CREATE TABLE MyTable
(
 key_col INTEGER NOT NULL UNIQUE, 
 data_col INTEGER
 CHECK (data_col = 55)
);

INSERT INTO MyTable (key_col, data_col)
   VALUES (1, NULL);

Le INSERTréussit pour cette ligne, même si la CHECKcondition est résolue NULL = NULL. Ceci doit être défini dans la norme SQL-92 ("ANSI"):

11.6 Définition des contraintes de table

3)

Si la contrainte de table est une définition de contrainte de contrôle, alors soit SC la condition de recherche contenue immédiatement dans la définition de contrainte de contrôle et soit T le nom de table inclus dans le descripteur de contrainte de table correspondant; la contrainte de table n'est pas satisfaite si et seulement si

EXISTE (SELECT * FROM T WHERE NOT (SC))

est vrai.

Lisez à nouveau attentivement, en suivant la logique.

En anglais simple, notre nouvelle ligne ci-dessus reçoit le «bénéfice du doute» sur le fait d'être UNKNOWNet d' être autorisé à passer.

Dans SQL DML, la règle de la WHEREclause est beaucoup plus simple à suivre:

La condition de recherche est appliquée à chaque ligne de T. Le résultat de la clause where est une table des lignes de T pour lesquelles le résultat de la condition de recherche est vrai.

En anglais simple, les lignes évaluées UNKNOWNsont supprimées du jeu de résultats.

un jour quand
la source
5

Chez technet, il y a une bonne explication du fonctionnement des valeurs nulles.

Null signifie inconnu.

Par conséquent, l'expression booléenne

valeur = null

n'évalue pas à false, il évalue à null, mais si c'est le résultat final d'une clause where, alors rien n'est retourné. C'est une manière pratique de le faire, car renvoyer null serait difficile à concevoir.

C'est intéressant et très important de comprendre ce qui suit:

Si dans une requête nous avons

where (value=@param Or @param is null) And id=@anotherParam

et

  • valeur = 1
  • @param est nul
  • id = 123
  • @ anotherParam = 123

puis

"value = @ param" évalue à null
"@param est nul" évalue à vrai
"id = @ anotherParam" évalue à vrai

Ainsi l'expression à évaluer devient

(nul ou vrai) et vrai

Nous pourrions être tentés de penser qu'ici "nul ou vrai" sera évalué à nul et donc l'expression entière devient nulle et la ligne ne sera pas retournée.

Ce n'est pas le cas. Pourquoi?

Parce que "nul ou vrai" est évalué à vrai, ce qui est très logique, puisque si un opérande est vrai avec l'opérateur Or, quelle que soit la valeur de l'autre opérande, l'opération retournera vrai. Ainsi, peu importe que l'autre opérande soit inconnu (nul).

Nous avons donc finalement true = true et donc la ligne sera retournée.

Remarque: avec la même logique limpide que «nul ou vrai» évalue à vrai, «nul et vrai» s'évalue à nul.

Mise à jour:
Ok, juste pour le rendre complet, je veux ajouter le reste ici aussi, ce qui s'avère assez amusant par rapport à ce qui précède.

"null ou faux" est évalué à null, "null et faux" est évalué à faux. :)

La logique est bien sûr toujours aussi évidente qu'avant.

Magnus
la source
4

Parce que NULLsignifie «valeur inconnue» et deux valeurs inconnues ne peuvent pas être égales.

Donc, si dans notre logique NULLN ° 1 est égal à NULLN ° 2, alors nous devons dire que d'une manière ou d'une autre:

SELECT 1
WHERE ISNULL(nullParam1, -1) = ISNULL(nullParam2, -1)

où la valeur connue -1N ° 1 est égale à -1N ° 2

Armen
la source
nullParam1 = -1et nullParam2 =NULLet accident d'avion ... devrait êtreISNULL(NULLIF(@nullParam1, @nullParam2), NULLIF(@nullParam2, nullParam1)) IS NULL
Selvin
4

Les réponses ici semblent toutes venir d'un point de vue CS, je veux donc en ajouter une du point de vue du développeur.

Pour un développeur NULL est très utile. Les réponses ici disent que NULL signifie inconnu, et peut-être que dans la théorie CS, c'est vrai, je ne m'en souviens pas, cela fait un moment. Dans le développement réel, du moins d'après mon expérience, cela se produit environ 1% du temps. L'autre 99% est utilisé pour les cas où la valeur n'est pas INCONNUE mais elle est CONNUE ABSENTE.

Par exemple:

  • Client.LastPurchase, pour un nouveau client. Ce n'est pas inconnu, on sait qu'il n'a pas encore fait d'achat.

  • Lors de l'utilisation d'un ORM avec un mappage Table par hiérarchie de classes , certaines valeurs ne sont tout simplement pas mappées pour certaines classes.

  • Lors du mappage d'une arborescence, une racine aura généralementParent = NULL

  • Et beaucoup plus...

Je suis sûr qu'à un moment donné WHERE value = NULL, la plupart des développeurs ont écrit , n'ont obtenu aucun résultat, et c'est ainsi qu'ils ont appris la IS NULLsyntaxe. Regardez simplement combien de votes cette question et les votes liés ont.

Les bases de données SQL sont un outil et elles doivent être conçues de la manière la plus facile à comprendre pour leurs utilisateurs.

AlexDev
la source
1
Tout le monde semble crier «NULL is unknown» puis justifier le comportement. Oui, si c'est une prémisse alors 3VL peut-être la réponse. Mais dans presque tous les DB sur lesquels je travaille, NULL signifie absent. Désolé ta voix est perdue dans le désert @AlexDev
John Rees
3

NULL n'est égal à rien, pas même à lui-même. Ma solution personnelle pour comprendre le comportement de NULL est d'éviter de l'utiliser autant que possible :).

Chris R. Timmons
la source
1
pourrait aussi bien être égal à tout, comme c'est le cas dans le cas des jointures gauche / droite / externe ...
Miguel Ventura
5
Quelle réponse stupide et improductive. On pourrait dire la même chose aux enfants du primaire au sujet de l'algèbre, mais sans reconnaître réellement ce que l'on essaie de résoudre, cela serait tout simplement ridicule, ce qu'il a fait.
Evan Carroll
2
@Evan: En fait, éviter NULL est une bonne solution. La logique à 3 valeurs n'est pas sans controverse, et beaucoup de gens pensent que SQL serait mieux sans NULL et toute la complexité (nécessaire) que cela implique.
sleske
3
«Beaucoup de gens» est un mot fou, et «pas sans controverse» est une façon de masquer le plus simple «controversé» dont 3VL n'est pas.
Evan Carroll
"NULL n'est égal à rien, pas même à lui-même." selon cette logique, <somevalue>! = NULL doit retourner true. Dans l'univers étrange de SQL, cependant, c'est faux.
Tom Lint
3

La question:
une inconnue équivaut-elle à une autre inconnue?
(NULL = NULL)
Cette question est une question à laquelle personne ne peut répondre, elle est donc par défaut true ou false en fonction de votre paramètre ansi_nulls.

Cependant la question:
cette variable inconnue est-elle inconnue?
Cette question est très différente et peut être répondue avec vrai.

nullVariable = null compare les valeurs
nullVariable est null compare l'état de la variable

user224385
la source
3

La confusion provient du niveau d'indirection (abstraction) qui résulte de l'utilisation de NULL .

Revenant à l'analogie de «ce qu'il y a sous le sapin de Noël», «Inconnu» décrit l'état des connaissances sur ce qui se trouve dans l'encadré A.

Donc, si vous ne savez pas ce qu'il y a dans la case A, vous dites que c'est "Inconnu", mais cela ne veut pas dire que "Inconnu" est à l'intérieur de la case . Quelque chose d'autre qu'inconnu se trouve dans la boîte, peut-être une sorte d'objet, ou peut-être rien n'est dans la boîte.

De même, si vous ne savez pas ce qu'il y a dans la case B, vous pouvez étiqueter votre état de connaissance du contenu comme étant "inconnu".

Alors, voici le kicker: votre état de connaissance sur la boîte A est égal à votre état de connaissance sur la boîte B . (Votre état de connaissance dans les deux cas est «Inconnu» ou «Je ne sais pas ce qu'il y a dans la boîte».) Mais le contenu des boîtes peut être égal ou non.

Pour revenir à SQL, idéalement, vous ne devriez pouvoir comparer les valeurs que lorsque vous savez ce qu'elles sont. Malheureusement, l'étiquette qui décrit un manque de connaissances est stockée dans la cellule elle - même , nous sommes donc tentés de l'utiliser comme valeur. Mais nous ne devrions pas utiliser cela comme une valeur, car cela conduirait à "le contenu de la boîte A égale le contenu de la boîte B lorsque nous ne savons pas ce qui est dans la boîte A et / ou que nous ne savons pas ce qui est dans la boîte B. (Logiquement, l'implication "si je ne sais pas ce qu'il y a dans la case A et si je ne sais pas ce qui se trouve dans la case B, alors ce qui se trouve dans la case A = ce qui se trouve dans la case B" est fausse.)

Ouais, cheval mort.

TomEberhard
la source
3

MSDN a un bel article descriptif sur les valeurs nulles et la logique à trois états qu'elles engendrent.

En bref, la spécification SQL92 définit NULL comme inconnu et NULL utilisé dans les opérateurs suivants provoque des résultats inattendus pour les non-initiés:

= operator NULL   true   false 
NULL       NULL   NULL   NULL
true       NULL   true   false
false      NULL   false  true

and op     NULL   true   false 
NULL       NULL   NULL   false
true       NULL   true   false
false      false  false  false

or op      NULL   true   false 
NULL       NULL   true   NULL
true       true   true   true
false      NULL   true   false
Paul Wagland
la source
Mais la question n'est pas de 3VL (logique à trois valeurs), c'est de la propriété réflexive de l'égalité.
MaD70
Pour être plus précis, comme je l'ai finalement détaillé dans ma réponse, des problèmes surviennent lorsque l'égalité est interprétée dans un 3VL de sorte que la propriété réflexive de l'égalité ne s'évalue pas toujours comme vraie.
MaD70
1

null est inconnu dans SQL donc nous ne pouvons pas nous attendre à ce que deux inconnues soient identiques.

Cependant, vous pouvez obtenir ce comportement en définissant ANSI_NULLS sur Off (il est activé par défaut) Vous pourrez utiliser l'opérateur = pour les valeurs nulles

SET ANSI_NULLS off
if null=null
print 1
else 
print 2
set ansi_nulls on
if null=null
print 1
else 
print 2
ps.
la source
2
C'est toutes sortes de non . Le monde a une définition de null, apprenez à la comprendre ou modifiez simplement la table pour avoir des types int et mettre à jour les colonnes.
Evan Carroll
3
Je n'ai vraiment pas recommandé SET ANSI_NULLS désactivé. J'ai découvert ANSI_NULLS à la dure. Mais il est toujours bon de connaître toutes les options disponibles, spécialement lorsque vous rencontrez une ligne qui dit Where SomeId = null Comment donner un sens à cette ligne sans connaître ANSI_NULLS. À mon avis, mon message était utile .. :)
ps.
1

Vous travaillez pour le gouvernement en enregistrant des informations sur les citoyens. Cela comprend la carte d'identité nationale de chaque personne dans le pays. Un enfant a été laissé à la porte d'une église il y a 40 ans, personne ne sait qui sont ses parents. L'ID du père de cette personne est NULL. Deux de ces personnes existent. Comptez les personnes qui partagent le même identifiant de père avec au moins une autre personne (personnes qui sont frères et sœurs). Comptez-vous ces deux-là aussi?

La réponse est non, non, car nous ne savons pas si ce sont des frères et sœurs ou non.

Supposons que vous n'ayez pas d' NULLoption, et que vous utilisiez à la place une valeur prédéterminée pour représenter «l'inconnu», peut-être une chaîne vide ou le chiffre 0 ou un caractère *, etc. Ensuite, vous auriez dans vos requêtes que * = * , 0 = 0, et «» = «», etc. Ce n'est pas ce que vous voulez (comme dans l'exemple ci-dessus), et comme vous pourriez souvent oublier ces cas (l'exemple ci-dessus est un cas marginal clair en dehors de la pensée quotidienne ordinaire ), alors vous avez besoin de la langue dont vous vous souviendrez que ce NULL = NULLn'est pas vrai.

La nécessité est la mère de l'invention.

Rashad Saleh
la source
0

Juste un ajout à d'autres réponses merveilleuses:

AND: The result of true and unknown is unknown, false and unknown is false,
while unknown and unknown is unknown.

OR: The result of true or unknown is true, false or unknown is unknown, while unknown or unknown is unknown.

NOT: The result of not unknown is unknown
Kiren Siva
la source
0

Si vous recherchez une expression retournant true pour deux NULL, vous pouvez utiliser:

SELECT 1 
WHERE EXISTS (
    SELECT NULL
    INTERSECT
    SELECT NULL
)

Il est utile si vous souhaitez répliquer des données d'une table à une autre.

Piotr
la source
0

Le test d'égalité, par exemple, dans une instruction case clause when, peut être modifié de

XYZ = NULL 

à

XYZ IS NULL

Si je veux traiter les espaces et les chaînes vides comme égaux à NULL, j'utilise souvent également un test d'égalité comme:

(NULLIF(ltrim( XYZ ),'') IS NULL)
Allan F
la source