2010-08-04 4 views
3

Pourquoi cette requête renvoie-t-elle 0 ligne?MySQL mystery: La valeur nulle n'est pas différente de la chaîne non nulle

select t.f1, t.f2 
from (select null f1, 'a' f2 from dual) t 
where t.f1<>t.f2; 

Ceci est une version distillée d'une requête complexe que j'ai. Je veux comparer deux tables contenant des données liées un-à-un et je veux sélectionner les lignes qui contiennent des valeurs différentes pour certains champs. Mais il peut aussi y avoir le cas où une ligne manque dans l'une des tables. Le LEFT JOIN renvoie correctement des valeurs null pour ces lignes, mais la clause WHERE filtre incorrectement (ou de manière inattendue) ces lignes. Pourquoi dans ce cas-ci, 'null' n'est PAS DIFFERENT à une valeur non nulle (comme 'a')?

Pourquoi?

Ce qui me rend fou est que ce

select t.f1, t.f2 
from (select null f1, 'a' f2 from dual) t; 

retourne 1 ligne (comme je m'y attendais), mais cette

select t.f1, t.f2 
from (select null f1, 'a' f2 from dual) t 
where t.f1=t.f2; 

renvoie 0 lignes !! Donc, null n'est pas égal à 'a' et null n'est pas différent de 'a' !!

S'il vous plaît ... Quelqu'un peut-il expliquer cela?

+0

Merci à tous ... oui J'avais déjà résolu mon problème pratique en ajoutant des conditions IS NULL à la clause WHERE. Cependant, j'ai été surpris que ni 'a' tato

+0

Je sais exactement ce que vous voulez dire, c'est une astuce logique sanglante dans le travail avec SQL. :) Même après des années de travaux SQL, je dois toujours faire le changement supplémentaire dans mon cerveau pour permettre les valeurs nulles. –

Répondre

5

Exactement. NULL représente une valeur inconnue, pas une valeur spécifique (ce n'est pas la même chose que NULL en C, ou nil en Ruby, etc.) En SQL, si vous comparez quelque chose à la valeur inconnue, le résultat est également inconnu. Et vous n'obtiendrez pas les lignes où la condition WHERE est inconnue.

Essayez ceci:

SELECT NULL <> 2; 

et vous verrez NULL comme résultat.

Essayez ceci:

SELECT * FROM t WHERE NULL; 

et aucune ligne sortiront, même si la table t est énorme.

Si vous avez vraiment besoin de ce que vous avez dit que vous vouliez (et je ne dis pas cela), vous pouvez faire quelque chose comme ceci:

SELECT T.f1, T.f2 
FROM (SELECT NULL f1, 'a' f2) T 
WHERE ((T.f1 IS NULL OR T.f2 IS NULL) 
    AND (T.f1 IS NOT NULL OR T.f2 IS NOT NULL)) 
    OR T.f1 <> T.f2 
0

Essayez de faire cette requête:

select * from dual where NULL = NULL 

Il retourne 0 lignes. C'est parce que pour comparer une valeur avec null, vous devez faire IS NULL ou IS NOT NULL, sinon il renverra false.

3

Le concept de NULL est une source commune de confusion pour les nouveaux arrivants à SQL , qui pensent souvent que NULL est traité comme les autres valeurs.

Ce n'est pas le cas. Conceptuellement, NULL signifie "une valeur inconnue manquante" et donc il est traité très différemment.

Ce que vous voyez est assez facile à expliquer. Prenons l'exemple suivant:

CREATE TABLE mytb (id int, value int); 

INSERT INTO mytb VALUES (1, 100); 
INSERT INTO mytb VALUES (2, 200); 
INSERT INTO mytb VALUES (3, NULL); 
INSERT INTO mytb VALUES (4, 400); 

Les moyens ci-dessus que pour la ligne avec id = 3, la valeur est « inconnu ». Il peut s'agir de 300 ou de 100 ou de toute autre chose.

Par conséquent, lorsque vous demandez ce qui suit:

SELECT * FROM mytb WHERE value <> 100; 
+------+-------+ 
| id | value | 
+------+-------+ 
| 2 | 200 | 
| 4 | 400 | 
+------+-------+ 
2 rows in set (0.00 sec) 

La ligne avec id = 3 n'est pas retourné, parce que NULL <> 100 retours "inconnu". Nous ne savons pas si la ligne id = 3 a la valeur 100, donc l'expression ne renvoie pas true. Je ne renvoie pas non plus false. Il renvoie "unknown" (NULL).

La condition de la clause WHERE ne peut être satisfaite que si l'expression est true. Lorsque vous comparez quelque chose à NULL, l'expression ne peut jamais être vraie. Ce sera "inconnu".

0

La valeur NULL n'est rien, elle ne peut pas être égale ou non à quelque chose. Si vous voulez vérifier si votre valeur est nulle - utiliser « IS NULL » déclaration:

select t.f1, t.f2 
from (select null f1, 'a' f2 from dual) t 
where t.f1 IS NULL 

Si vous voulez vérifier si vos valeurs sont égales ou non égales - vous pouvez utiliser COALESCE fonction sur les colonnes nullable:

select t.f1, t.f2 
from (select null f1, 'a' f2 from dual) t 
where COALESCE(t.f1, '')<>COALESCE(t.f2, ''); 
+0

La fonction s'appelle 'COALESCE'. – Amadan

+0

oh, bien sûr que vous avez raison. mais le lien était correct en passant :) –

Questions connexes