2011-06-24 43 views
2

我有一個問題,我想刪除孤立的記錄。我想知道刪除不在聯接中的記錄的語法是什麼。如何刪除不在2個表的連接中的內容?

所以,如果我的查詢得到的東西(即我不想刪除的):

select * from tbl_user tu 
inner join tbl_user_group_xref tugx on tu.userid=tugx.userid 

那怎麼辦我 1)得到的是心不是在從句中和2)刪除它的東西嗎?

就像不使用數組一樣,但數組解決方案對於學習目的仍然有用。

+0

您試圖從哪個表中刪除? –

+0

「不在2個表格的連接中的東西」被稱爲[antijoin](http://en.wikipedia.org/wiki/Relational_algebra#Antijoin_.28.E2.96.B7.29)。 – onedaywhen

+0

非常感謝,@duncan即時消息不刪除從表中刪除一切不在聯接。 – Exitos

回答

3

鄧肯豪的答案有一個優化,我知道在MySQL中工作,並可能與其他服務器一起工作。它可能也適用於t-clausen.dk在MySQL中的回答。

如果您從表t1中刪除行中沒有相應行的行,並且這兩個表都非常大,那麼服務器最終可能會陷入磁盤搜索。我發現,如果您可以強制服務器在運行查詢之前將t2索引加載到內存中,然後在查詢中強制服務器忽略t1的索引,性能可以得到很大提高。這使服務器執行t1的順序掃描,這將是磁盤的有效使用。服務器逐步遍歷t1的每一行,查找內存中的t2索引,以確定是否應刪除該行。磁盤尋道因此被淘汰,磁盤IO速率非常高,這使CPU很忙。

例如:

delete tbl_user 
    from tbl_user tu ignore key (primary) 
    left join tbl_user_group_xref tugx 
    use key (userid) on tu.userid=tugx.userid 
where tugx.userid is null 

(我假設tbl_user.userid在其表的PK和tbl_user_group_xref.userid索引被命名爲userid如果不是,改變各自的鍵名。)

強制服務器將索引加載到內存中是技術特定的。在MyISAM表的MySQL中,您可以使用load index into cache。重新創建索引(在MySQL中速度非常快)可能會將其留在緩存中(並且會對平衡B樹有很好的副作用)。

我見過使用這種優化的例子,其性能遠遠超過100倍。只要您可以緩存t2的索引,就可以高效地處理非常大的表。

6

如:

delete from tbl_user tu 
where 
    user_id not in (
    select 
     user_id 
    from 
     tbl_user tu 
    inner join 
     tbl_user_group_xref tugx on tu.userid=tugx.userid 
) 
+0

你還沒有加入你的表tbl_user與子選擇,使得它很慢,如果有很多的用戶。 –

+1

遺憾的是,這是被接受的,因爲最好學習一下'left loin'是什麼,它與「inner join」有什麼不同,以及爲什麼它比鼓勵任何人使用子查詢效率低一。任何關心表現的人都應該比較Duncan Howe或t-clausen.dk答案的效率。 – 2011-06-24 14:41:18

+0

也許其中一個「神」會改變它。這真的是一個經典的錯誤,很難過看到它「贏」 –

1

可以使用NOT IN語句喜歡這裏描述http://www.techonthenet.com/sql/in.php

基本上你會寫從表中選擇查詢,你想從刪除的記錄,然後執行NOT IN連接兩個表的子查詢。

雖然我不知道這是否是非常好的性能。

編輯:基本上正是什麼Heximal說。

6

嘗試

delete tbl_user 
    from tbl_user tu 
    left join tbl_user_group_xref tugx on tu.userid=tugx.userid 
where tugx.userid is null 
+0

這是一個很好的答案,但我認爲我更喜歡十進制答案,因爲它更具表現力 – Exitos

+1

@ Pete2k,你應該接受這個答案。它適當的可擴展性和快速,而十六進制將生成一個潛在的非常大的臨時表。 – 2011-06-24 11:17:56

+0

@fsb - 非常感謝 –

1

此DELETE語句從鄧肯豪腳本執行最佳的爲好。我給Duncan Howe一個加號,因爲它是正確的,我不知道這個語法。

delete tu 
from tbl_user tu 
where not exists (select 1 from tbl_user_group_xref where userid = tu.userid) 
+0

Duncan Howe給出的'left join ___ where ___ is null'是一個非常好的解決方案。 Down被認爲是「唯一正確的方式」,而良好的工程師應該知道的通常不是事實。否則,我更喜歡這個'不在(子查詢)'這似乎有問題。 – 2011-06-24 11:26:47

+0

「最好的答案」是一個可以被捍衛的判斷,而「唯一正確的方式」根本不正確,並且使其他答案錯誤。刪除該評論,我會刪除我的投票。 – 2011-06-24 11:31:56

+1

避免'不在(子查詢)'中,我在我的博客上寫了它,我的sql表現更好。 –