2013-05-01 65 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