2011-06-14 34 views
0

在Rails 3(也有,如果你觉得在你的查询中使用它meta_where宝石),我得到了我一直在敲打我的头一个真正棘手的查询:整蛊Rails3中/ MySQL查询

假设我有两个模型,顾客和购买,顾客有很多购买。让我们将至少有两件购物的顾客定义为“repeat_customer”。我需要每天找repeat_customers总数在过去的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.allPurchase.all相同的路线查询,然后做了一堆计算的红宝石。我更喜欢在mysql中进行选择,分组和计算,因为它不仅速度更快,而且还减少了数据库中的带宽。在大型数据库中,上面的代码基本上是无用的。

我一直在尝试一段时间来召唤rails/active_record中的查询,但即使使用meta_where gem也没有运气。如果必须的话,我也会接受纯粹的mysql查询解决方案。

编辑:我会缓存它(或添加一个“重复”字段给客户),虽然只是为了这个简化的问题。客户在任何时候都可以改变重复客户的标准(2次购买,3次购买,4次购买等),所以不幸的是我不得不在现场进行计算。

+0

您是否可以创建一张缓存此信息并在购买时生成该信息的表格。这样就没有计算开销,你只需要为用户计算一次状态。 – 2011-06-14 01:19:53

+0

这并不直接回答,但为了扩展Devin的评论,您可以向客户添加一个名为repeat_status_date的列,并在购买对象上使用after_save回调进行编写。 – 2011-06-14 01:44:53

+0

我会缓存它(或为客户添加一个“重复”字段),但仅限于此简化问题。客户在任何时候都可以改变重复客户的标准(2次购买,3次购买,4次购买等),所以不幸的是我不得不在现场进行计算。 – Charles 2011-06-14 17:19:59

回答

0
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 

我没有丝毫的测试,所以我希望它的作品。另外,我希望我能理解你正在努力完成的事情。

但请注意,你不应该这样做,它会太慢。由于数据在一天过去之后永远不会改变,因此每天只需缓存一次。

+0

我会缓存它(或为客户添加“重复”字段),但仅限于此简化问题。客户在任何时候都可以改变重复客户的标准(2次购买,3次购买,4次购买等),所以不幸的是我不得不在现场进行计算。 – Charles 2011-06-14 17:19:50

+0

如果此代码能够正常工作,很高兴收到回复。 – Ariel 2011-06-15 06:57:40