2009-06-16 8 views
23

Espero que el resultado de la tercera consulta siguiente contenga id = 732. No es así ¿Porqué es eso?MySQL SELECCIONE x FROM a WHERE NOT IN (SELECCIONAR x FROM b) - Resultado inesperado

 
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) 

Hay tres entradas NULL en la tabla email.id, y no hay entradas NULL en match.id.

La tabla completa/consultas se pueden ver en http://pastebin.ca/1462094

Respuesta

39

De documentation:

Para cumplir con la norma SQL, IN vuelve NULL no sólo si la expresión en el lado izquierdo es NULL, pero también si no se encuentra una coincidencia en la lista y una de las expresiones en la lista es NULL.

Este es exactamente tu caso.

Ambos IN y NOT IN devuelven NULL que no es una condición aceptable para WHERE cláusula.

reescribir su consulta como sigue:

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

¿Es el caso del OP? Según tengo entendido, "si no se encuentra ninguna coincidencia y una de las expresiones en la lista es NULA", no es el caso, ya que debería encontrarse 732, lo que invalidaría esa cláusula, ¿no? – Eric

+0

@Eric: 732 no se encuentra en los correos electrónicos. – Quassnoi

+0

@Quassnoi: Tienes razón, lapso de cerebro :) – Eric

5

estoy un poco fuera de contacto con los detalles de cómo MySQL se ocupa de los nulos, pero aquí hay dos cosas para probar:

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 segunda consulta parece contra intuitiva, pero cumple la condición de unión y luego la condición de dónde. Este es el caso donde las cláusulas join y where no son equivalentes.

+0

Según tengo entendido, el uso de una unión externa izquierda también es mejor para el rendimiento. –

31

... o si realmente desea utilizar NOT IN se puede utilizar

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

Esto funcionó para mí, quería crear un menú desplegable de "tipos de medidores" que no habían sido seleccionados, es decir, no tenía registros en la segunda tabla – zzapper

+1

Prefiero esta respuesta. No sabía que "donde id no es nulo nulo" era necesario para que la consulta "no en" funcione. – marlar

-1

Aquí es un poco de SQL que realmente tiene sentido:

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

Simple siempre es mejor.

Cuestiones relacionadas