2009-06-16 6 views
23

Je m'attends à ce que le résultat de la troisième requête ci-dessous contienne id = 732. Ce n'est pas le cas. Pourquoi donc?MySQL SELECT x À PARTIR D'UN O WH PAS DANS (SELECT x FROM b) - Résultat inattendu

 
mysql> SELECT id FROM match ORDER BY id DESC LIMIT 5 ; 
+------------+ 
|   id | 
+------------+ 
|  732 | 
|  730 | 
|  655 | 
|  458 | 
|  456 | 
+------------+ 
5 rows in set (0.00 sec) 

mysql> SELECT id FROM email ORDER BY id DESC LIMIT 5 ; 
+------------+ 
|   id | 
+------------+ 
|  731 | 
|  727 | 
|  725 | 
|  724 | 
|  723 | 
+------------+ 
5 rows in set (0.00 sec) 

mysql> SELECT * FROM match WHERE id NOT IN (SELECT id FROM email) ; 
Empty set (0.00 sec) 

Il y a trois entrées NULL dans le tableau email.id, et aucune entrée NULL dans match.id.

Le tableau complet/requêtes peut être vu à http://pastebin.ca/1462094

Répondre

39

De documentation:

Pour se conformer à la norme SQL, IN rendements NULL non seulement si l'expression du côté gauche est NULL, mais aussi si aucune correspondance se trouve dans la liste et l'un des les expressions de la liste sont NULL.

C'est exactement votre cas.

Les deux IN et NOT IN renvoient NULL ce qui n'est pas une condition acceptable pour la clause WHERE.

Ressaisissez votre requête comme suit:

SELECT * 
FROM match m 
WHERE NOT EXISTS 
     (
     SELECT 1 
     FROM email e 
     WHERE e.id = m.id 
     ) 
+0

Est-ce le cas de l'OP? Ma compréhension était que le "si aucune correspondance est trouvé et l'une des expressions dans la liste est NULL" n'est pas le cas puisque 732 devrait être trouvé, invalidant ainsi cette clause, non? – Eric

+0

@Eric: 732 n'est pas trouvé dans les emails. – Quassnoi

+0

@Quassnoi: Vous avez raison, cerveau laps :) – Eric

5

Je suis un peu hors de contact avec les détails de la façon dont MySQL gère les valeurs nulles, mais voici deux choses à essayer:

SELECT * FROM match WHERE id NOT IN 
    (SELECT id FROM email WHERE id IS NOT NULL) ; 

SELECT 
    m.* 
FROM 
    match m 
    LEFT OUTER JOIN email e ON 
     m.id = e.id 
     AND e.id IS NOT NULL 
WHERE 
    e.id IS NULL 

La deuxième requête semble contre-intuitive, mais elle exécute la condition de jointure, puis la condition where. C'est le cas où les clauses join et where ne sont pas équivalentes.

+0

Ma compréhension est que l'utilisation d'une jointure externe gauche est également préférable pour les performances. –

31

... ou si vous voulez vraiment utiliser NOT IN vous pouvez utiliser

SELECT * FROM match WHERE id NOT IN (SELECT id FROM email WHERE id IS NOT NULL) 
+0

Cela a fonctionné pour moi, voulait créer une liste déroulante de "types de compteurs" qui n'avaient pas déjà été sélectionnés, c'est à dire n'avait pas d'enregistrements dans la deuxième table – zzapper

+1

Je préfère cette réponse. Je ne savais pas que "où id n'est pas null null" était nécessaire pour que la requête "not in" fonctionne. – marlar

-1

Voici quelques SQL qui font vraiment sens:

SELECT m.id FROM match m LEFT JOIN email e ON e.id = m.id WHERE e.id IS NULL 

Simple est toujours mieux.

Questions connexes