2009-06-16 4 views
23

Я ожидаю, что результат третьего запроса ниже содержит id = 732. Это не так. Почему это?MySQL SELECT x FROM WHERE NOT IN (SELECT x FROM b) - Неожиданный результат

 
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) 

В таблице email.id есть три записи NULL, а в match.id нет записей NULL.

Полный стол/запросы можно увидеть на http://pastebin.ca/1462094

ответ

39

От documentation:

В соответствии со стандартом SQL, IN возвращает NULL не только тогда, когда выражение на левой стороне находится NULL, но и, если совпадение не найдено в списке и один из выражения в списке: NULL.

Это именно ваш случай.

Оба IN и NOT IN return NULL, что не является приемлемым условием для статьи WHERE.

Перепишите запрос следующим образом:

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

Это случай OP? Мое понимание заключалось в том, что «если совпадение не найдено и одно из выражений в списке равно NULL», это не так, так как 732 должно быть найдено, тем самым недействительным это предложение, правильно? – Eric

+0

@ Эрик: 732 не найден в письмах. – Quassnoi

+0

@Quassnoi: Вы правы, пробел в мозге :) – Eric

5

Я немного оторваны с деталями, как MySQL занимается нулям, но вот две вещи, чтобы попробовать:

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 

Второй запрос выглядит как интуитивно понятный, но он выполняет условие соединения, а затем условие where. Это случай, когда объединения и где предложения не эквивалентны.

+0

Мое понимание заключается в том, что использование внешнего внешнего соединения лучше для производительности. –

31

... или, если вы действительно хотите использовать NOT IN вы можете использовать

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

Это сработало для меня, хотелось создать выпадающее меню «Тип счетчика», которое еще не было выбрано, т. Е. Не было записей во второй таблице – zzapper

+1

Я предпочитаю этот ответ. Не знал, что «где id не null null» был необходим, чтобы заставить работать «не в». – marlar

-1

Вот некоторые SQL, которые на самом деле имеет смысл:

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

Простой всегда лучше.

Смежные вопросы