Rails 3查询关联计数的条件

时间:2011-06-11 02:03:38

标签: mysql ruby ruby-on-rails-3

在使用mysql的Rails 3中,假设我有两个模型,Customers和Purchases,显然是购买belongs_to客户。我想找到2个或更多订单的所有客户。我可以简单地说:

Customer.includes(:purchases).all.select{|c| c.purchases.count > 2}

但实际上,上面的行会查询Customer.all和Purchase.all的大小,然后选择"选择"红宝石中的类型处理。在一个大型数据库中,我更愿意避免做所有这些"选择"在ruby中计算,并让mysql做处理,只给我合格的客户列表。这要快得多(因为mysql更多地调整了这一点)并且显着减少了数据库的带宽。

不幸的是,我无法用rails中的构建块(where,having,group等)来实现代码,以实现这一点,这就是(psudo-code):

Customer.joins(:purchases).where("count(purchases) > 2").all

我会解决直接的MySql解决方案,尽管我更喜欢在优雅的rails框架中解决这个问题。

3 个答案:

答案 0 :(得分:73)

无需安装宝石即可使其工作(虽然metawhere很酷)

Customer.joins(:purchases).group("customers.id").having("count(purchases.id) > ?",0)

答案 1 :(得分:9)

此时此文档的文档相当稀少。如果您要再进行与此类似的查询,我会考虑使用Metawhere。使用Metawhere,你可以这样做(或类似的东西,不确定语法是否完全正确):

Customer.includes(:purchases).where(:purchases => {:count.gte => 2})

这样做的好处是MetaWhere仍然使用ActiveRecord和arel来执行查询,因此它可以使用'new'trailway 3进行查询。

此外,您可能不希望最后调用.all,因为这会导致查询ping数据库。相反,您希望使用延迟加载而不是命中数据库,直到您实际需要数据(在视图中,或处理实际数据的其他方法。)

答案 2 :(得分:0)

这有点冗长,但如果你想要客户where count = 0或更灵活的sql,你会做LEFT JOIN

Customer.joins('LEFT JOIN purchases on purchases.customer_id = customers.id').group('customers.id').having('count(purchases.id) = 0').length