2010-07-22 18 views
32

我有兩個表(任務和Timeentries),這是由一個外鍵連接引用(TimeEntries.TaskID引用Tasks.ID)刪除行優雅的方式,它不被其他表

現在,我想刪除未被TimeEntries表引用的任務中的所有行。我認爲這應該工作:

DELETE FROM Tasks WHERE ID not IN (SELECT TaskID FROM TimeEntries) 

但它影響0行,即使在任務表中有很多未引用的行。

這裏有什麼問題?當然,我可以編寫一個迭代所有行的SP,但似乎可以在一行中完成。

我想這是睡眠時間下溢錯誤之一。請幫忙!

+2

如果你自己運行SELECT子查詢,你會得到預期的結果嗎? – JNK 2010-07-22 20:00:45

+0

@ J-N-K:是的,我做到了。 – 2010-07-22 23:02:47

回答

49

有一個臭名昭着的陷阱not in。基本上,id not in (1,2,3)是簡寫:

id <> 1 and id <> 2 and id <> 3 

現在,如果你TimeEntries表包含的null一個TaskID任何排,not in翻譯爲:

ID <> null and ID <> 1 and ID <> 2 AND ... 

null比較的結果總是unknown 。由於unknown在SQL中不成立,因此where子句會過濾掉所有行,並且最終不會刪除任何內容。

一個簡單的辦法是額外的,其中的子查詢子句:

DELETE FROM Tasks 
WHERE ID not IN 
     (
     SELECT TaskID 
     FROM TimeEntries 
     WHERE TaskID is not null 
     ) 
+0

你有建議如何解決這個問題嗎? – DOK 2010-07-22 20:03:10

+0

@DOK:當然,有一種方法添加到答案中。 SQLMenace發佈了另一個不錯的答案 – Andomar 2010-07-22 20:04:22

+0

優秀的答案。非常感謝! – 2010-07-22 23:00:04

3
Delete FROM Tasks 
     WHERE not Exists 
      (SELECT 'X' FROM TimeEntries where TimeEntries.TaskID = Tasks.ID) 

上面的SQL應刪除時間條目表中不存在Task.ID的任務中的所有行。我會運行它作爲選擇語句首先測試:)

9

由於您運行SQL 2008,您可以使用漂亮的新的合併語法。

MERGE Tasks AS target 
USING TimeEntries as Source ON (Target.TaskID=Source.TaskID) 
WHEN NOT MATCHED BY Source THEN DELETE; 
+1

+1:在這種情況下有點矯枉過正,但瞭解合併命令肯定有用。我甚至不知道這樣的東西存在。 – 2010-07-22 23:15:50

+1

你爲什麼認爲這是過度殺傷力?它非常適合這樣的任務(匹配表之間的行)。 – JohnFx 2010-07-23 04:32:28

+1

與以前的解決方案相比,它的性能如何?它是否有任何優勢,或者這是支持這種行爲的方式嗎? Thx – 2013-09-03 22:21:27

3

我知道這是老了,但我不知道爲什麼描述here沒有人提到刪除查詢。因此,僅供參考:

DELETE FROM Tasks 
FROM Tasks LEFT OUTER JOIN 
    TimeEntries ON TimeEntries.TaskID = Tasks.ID 
WHERE TimeEntries.TaskID IS NULL; 

此語法不是ISO兼容的,所以只適用於T-SQL。