在rails 3中(如果你想在查询中使用meta_where gem,也可以使用它),我得到了一个非常棘手的查询,我一直在努力:
假设我有两个模型,客户和采购,客户有很多采购。让我们将至少购买了2次的客户定义为"repeat_customer"。我需要找到过去3个月每天的重复客户总数,类似于:
Date TotalRepeatCustomerCount
1/1/11 10 (10 repeat customers by the end of 1/1/11)
1/2/11 15 (5 more customer gained "repeat" status on this date)
1/3/11 16 (1 more customer gained "repeat" status on this date)
...
3/30/11 150
3/31/11 160
基本上,我需要根据第二次购买的创建日期对客户数量进行分组,因为那是他们"获得重复状态"的时候。
当然,这可以在ruby中实现,比如:
Customer.includes(:purchases).all.select{|x| x.purchases.count >= 2 }.group_by{|x| x.purchases.second.created_at.to_date }.map{|date, customers| [date, customers.count]}
然而,上面的代码将在Customer.all
和Purchase.all
的同一行上激发查询,然后在ruby中进行一系列计算。我更喜欢在mysql中进行选择、分组和计算,因为它不仅速度快得多,还减少了数据库的带宽。在大型数据库中,上面的代码基本上是无用的。
一段时间以来,我一直在尝试在rails/active_record中创建查询,但即使使用了漂亮的meta_where gem也没有成功。如果必须的话,我也会接受纯mysql查询的解决方案。
编辑:我会缓存它(或者给客户添加一个"重复"字段),尽管只是针对这个简化的问题。重复客户的标准可以在任何时候由客户更改(2次购买、3次购买、4次购买等),所以不幸的是,我必须当场计算。
SELECT p_date, COUNT(customers.id) FROM
(
SELECT p_date - INTERVAL 1 day p_date, customers.id
FROM
customers NATURAL JOIN purchases
JOIN (SELECT DISTINCT date(purchase_date) p_date FROM purchases) p_dates
WHERE purchases.purchase_date < p_date
GROUP BY p_date, customers.id
HAVING COUNT(purchases.id) >= 2
) a
GROUP BY p_date
我一点也没有测试,所以我希望它能起作用。此外,我希望我能理解你正在努力实现的目标。
但请注意,你不应该这样做,太慢了。由于数据一天过去就不会改变,所以只需每天缓存即可。