2013-01-14 35 views
1

我試圖清理SQL Server中的一些數據,並在兩個表之間添加一個外鍵。排除空值在子查詢中返回0行

我想刪除一個表中的大量孤行。我不知道爲什麼以下查詢將在MS SQL服務器中返回0行。

- 這查詢不返回行

SELECT * FROM tbl_A其中ID不

(從tbl_B 選擇不同的ID)當我有沒有在子查詢,我得到空我期望的結果。

- 返回行包含所有的tbl_A的記錄,但不能在tbl_B

SELECT * FROM tbl_A其中ID不是(從tbl_B 選擇不同的ID,其中ID不爲null)

ID列可以爲空並且包含空值。如果我只運行子查詢,我會得到完全相同的結果,除了第一個查詢返回一個額外的NULL行像預期的那樣。

+0

[SQL NOT IN約束和NULL值]的可能重複(http://stackoverflow.com/questions/129077/sql-not-in-constraint-and-null-values) –

回答

2

這是NOT IN子查詢的預期行爲。當子查詢返回單個nullNOT IN將不匹配任何行。

如果你不完全想做null檢查,那麼你將要使用NOT EXISTS

select * 
from tbl_A A 
where not exists (select distinct ID 
        from tbl_B b 
        where a.id = b.id) 

至於爲何NOT IN導致的問題,這裏有一些職位,討論:

NOT IN vs. NOT EXISTS vs. LEFT JOIN/IS NULL

NOT EXISTS vs NOT IN

What's the difference between NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULL?

0

您可能已將ANSI NULL關閉。這比較空值,所以null = null將返回true。

前綴與

SET ANSI_NULLS ON 
GO 
+0

ANSI_NULLS通常處於打開狀態。當它在Null = Null時返回Null。如果關閉它,那麼Null = Null將返回true。 – TimothyAWiseman

+0

好點。編輯 – Jaloopa

1

匹配上NULL與等於(=)將返回NULL或UNKNOWN作爲從邏輯的觀點來看相對於真/假的第一查詢。例如。討論請參閱http://msdn.microsoft.com/en-us/library/aa196339(v=sql.80).aspx

如果您希望包含在表A中查找NULL值(表B中沒有NULL)(如果B是「父」,A是您希望的「外鍵」關係中的「子」),那麼您將需要第二個聲明,如下所示。此外,我會建議使用表前綴或別名來限定ID字段,因爲字段名稱在兩個表中都是相同的。最後,我不建議將NULL值作爲關鍵字。但無論如何:

select * from tbl_A as A where (A.ID not in (select distinct B.ID from tbl_B as B)) 
    or (A.ID is NULL and not exists(select * from tbl_B as B where B.ID is null)) 
0

問題是空值的不可比性。如果你問的是「不在」,而且子查詢中有空值,那麼就不能說任何事情肯定沒有,因爲它將這些空值視爲「未知」,因此三個值邏輯中的答案總是「未知」該SQL使用。

當然,這都是假設你有ANSI_NULLS ON(這是默認設置)如果你關閉它,那麼突然NULLS變得可比,它會給你結果,並且可能會給你期望的結果。

0

如果ID從不爲負,你可能會考慮這樣的:

select * 
from tbl_A 
where coalesce(ID, -1) not in (select distinct coalesce(ID, -1) from tbl_B) 

(或者,如果id是一個字符串,使用的東西線coalesce(id, '<null>'))。

這可能不適用於所有情況,但它具有編碼級別簡單的優點。