2013-05-01 122 views
0

我有一個模型用戶thats has_many user_entitlements。我想要獲得所有具有預覽屬性並且沒有用戶權利的用戶。Rails高級sql查詢

我的代碼是目前:

User.where("preview is not null").keep_if {|user| user.user_entitlements.empty?} 

這是通過所有用戶的迭代,看他們是否有任何用戶權利。

有沒有一種方法可以在SQL中做到這一點,使其更有效率,避免必須通過每個用戶?

回答

1

您可以使用Arel構建一個利用NOT EXISTS的查詢。

user_arel = User.arel_table 
ue_arel = UserEntitlement.arel_table 
User.where("preview is not null").where(
    UserEntitlement.where(ue_arel[:user_id].eq(user_arel[:id])).exists.not 
) 

我正在你的架構中的假設,即UserEntitlement包含user_id列。

+0

Awesome-謝謝! – BC00 2013-05-01 16:41:46

1

就更簡單了,你可以用includes強制LEFT JOIN,然後檢查NULL:

User.includes(:user_entitlements). 
    where("users.preview IS NOT NULL AND user_entitlements.id IS NULL") 
+0

如果存在大量數據集,您將'often_'在'LEFT JOIN'上看到'NOT EXISTS'更好的性能。來源:http://explainextended.com/2009/09/15/not-in-vs-not-exists-vs-left-join-is-null-sql-server/編輯:澄清你_often_看到更好的表現,考慮下面的PinnyM的評論。 – 2013-05-01 18:04:24

+1

@DanReedy,這將取決於DBMS和版本 - 只有查詢優化器可以確定將如何執行特定的查詢和分析。您鏈接的文章來自3.5年前,並且是SQL Server特有的。我不確定當前版本的MySQL(或SQL Server)在這方面是否更好,但需要確定。 – PinnyM 2013-05-01 18:10:59

+0

@DanReedy,我更喜歡你的方法順便說一句,但是ActiveRecord會讓這些亂七八糟的東西寫出來。太糟糕了,沒有寶石可以將其作爲原生行爲添加,因爲這是一種相當常見的情況。也許有一天... – PinnyM 2013-05-02 14:22:18