2009-06-16 146 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

這正是你的情況。

INNOT IN返回NULL這不是WHERE子句的可接受條件。

重寫查詢如下:

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

這是OP的情況嗎?我的理解是,「如果找不到匹配並且列表中的一個表達式爲NULL」不是這種情況,因爲應該找到732,從而使該條款無效,對吧? – Eric 2009-06-16 12:35:30

+0

@Eric:732在電子郵件中找不到。 – Quassnoi 2009-06-16 12:37:52

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條件。這種情況下,連接和where子句是不等價的。

+0

我的理解是,使用左外連接對於性能也更好。 – 2014-05-27 23:46:45

31

...或者,如果你真的想使用NOT IN可以使用

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

下面是一些SQL實際意義:

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

簡單總是比較好。

相關問題