在使用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框架中解决这个问题。
答案 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