2011-07-29 30 views
6

這看起來很基本,我對缺乏更好的單詞感到驚訝。我有兩個表,讓我們稱他們albumsartistsNull和IN()提供了意想不到的結果

CREATE TABLE `albums` (
    `album_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `artist_id` bigint(20) DEFAULT NULL, 
    `name` varchar(200) NOT NULL, 
    PRIMARY KEY (`album_id`) 
) 
CREATE TABLE `artists` (
    `artist_id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `name` varchar(250) NOT NULL, 
    PRIMARY KEY (`artist_id`) 
) 

有每個表幾十萬reconds。有些專輯行的空值爲artist_id,這是預期的。

然而,當我執行以下查詢找到藝術家,而不專輯:

SELECT * FROM artists WHERE artist_id NOT IN (SELECT artist_id FROM albums)

...查詢返回結果爲零。我知道這是不正確的。所以,我想這一個:

SELECT * FROM artists WHERE artist_id NOT IN (SELECT artist_id FROM albums WHERE artist_id IS NOT NULL)

...我回來一對夫婦一千行。我的問題是:爲什麼第一個查詢似乎在任何數字= NULL的想法上運行?或者這是一個奇怪的效果,NULL在IN()聲明?我覺得這是我錯過的基本東西。我通常不會在我的數據庫表中使用NULL。

回答

7

這就是爲什麼NOT EXISTS語義正確

SELECT * FROM artists ar 
WHERE NOT EXISTS 
    (SELECT * FROM albums al WHERE ar.artist_id = al.artist_id) 

邏輯:

  • NOT IN (x, y, NULL)實際上是
    • NOT (x OR y OR NULL)實際上是
      • (NOT x) AND (NOT y) AND (NOT NULL)

所以NULL無效整個NOT IN

+0

似乎不存在也稍微快一點。非常感謝您的信息! –

7

快速回答 - IN聲明是=a OR =b OR ...的快捷方式。如果你在這個列表中包含空值,那麼我認爲這是違反了聲明。你的第二個選擇可能是一個更好的選擇。

或者使用連接也可能工作,並且效率更高。

+0

true或未知評估爲true。這是一個不在:它有不同的分解 – gbn

2

它與方式做SQL NULL的解釋 - 你必須把它們看作未知值。

可以說你已經artist_id = 1

如果您運行以下命令:

artist_id = NULL 

而不是得到一個 '假' - 你得到 '未知';

當您運行諸如你的查詢時,只返回評估爲'TRUE'的值。

artist_id IN (NULL, NULL, NULL...) = UNKNOWN 
artist_id NOT IN (NULL, NULL, NULL....) = UNKNOWN 
+0

夠公平的,雖然我會反駁 - 爲什麼要使用null?如果這是我的數據庫設計,那麼當沒有藝術家時,我會用0代替null。爲什麼應該使用null來代替任何令人信服的理由? –

+0

它的確值得商榷。我個人使用它們作爲方便的佔位符 - 如果我加載一個經常有許多未知字段的表,而不是始終必須設置空值(即'',n/a等),我只是堅持NULL。我對這種方法很滿意 - 儘管有些人會考慮這種不好的做法。 – chris

+2

@Chris,有人認爲使用佔位符值會更混亂,因爲查看數據的任何人都必須知道哪個值是佔位符。它不是一個通用的解決方案,因爲總是會有設計中沒有合理的佔位符值可供選擇。使用NULL也有實際的好處 - 它在表和索引中都需要較少的存儲空間,因此也可以提高性能。 –

相關問題