2010-09-21 26 views
4

在軌我有2個表:如何選擇記錄,其中一個孩子不存在

bans(ban_id, admin_id) 
ban_reasons(ban_reason_id, ban_id, reason_id) 

我想找到所有的bans一定管理員那裏是在ban_reasons表中沒有記錄。我如何在Rails中執行此操作,而無需循環遍歷所有禁用記錄,並用ban.ban_reasons.nil?篩選出所有這些記錄(我希望使用單個SQL語句執行此操作)。

我只需要做到:(但我想這樣做的「軌」的方式)

SELECT bans.* FROM bans WHERE admin_id=1234 AND 
           ban_id NOT IN (SELECT ban_id FROM ban_reasons) 

回答

2

您的解決方案的偉大工程(只有一個要求),但它幾乎是普通的SQL:

bans = Ban.where("bans.id NOT IN (SELECT ban_id from ban_reason)") 

你也可以嘗試以下內容,讓鐵軌做的工作的一部分:

bans = Ban.where("bans.id NOT IN (?)", BanReason.select(:ban_id).map(&:ban_id).uniq) 
+0

兩者之間有什麼表現差異?第二個是否會導致更多的查詢? – 2010-09-21 20:11:42

+0

是的,你會得到1更多的查詢與第二個...我認爲性能問題真的取決於你的數據庫大小。 – Yannis 2010-09-22 13:17:00

+0

我猜如果目標是使用Rails,那麼這個建議就可以工作,但是對於大型數據集來說,性能會受到嚴重影響。 – 2013-02-01 14:22:23

2

的ActiveRecord只讓你一個點,之後的一切應以原始的SQL語句來完成。關於AR的好處是,它可以很容易地做到這一點。

但是,由於Rails 3,您可以使用AREL API執行幾乎所有的操作,儘管原始SQL可能看起來也可能看起來不太可讀。

我會去與原始的SQL,這裏是你的,如果沒有執行好,你可以嘗試另一個查詢:

SELECT  b.* 
FROM   bans b 
LEFT JOIN ban_reason br on b.ban_id = br.ban_id 
WHERE  br.ban_reason_id IS NULL 
+0

這將在大多數數據庫的表現比上面的其他更好。許多分貝具有相當差的IN性能(他們發現集合)。這在搜索連接上的空值時也會有一定的性能影響,但我仍然認爲它可能比上述更好。 – Scott 2011-04-08 20:57:30

+0

將它作爲NOT EXISTS()實現將是我想這個查詢更自然的語法,但我認爲你是對的,SQL是要走的路。 – 2013-02-01 14:30:56

0

使用Where Exists寶石(我的作者):

Ban.where(admin_id: 123).where_not_exists(:ban_reasons) 
相關問題