MySQL - 随着时间的推移,重复客户与新客户的查找订单

时间:2015-02-12 05:02:20

标签: mysql sql

我有一个包含orders_id,customers_email_address和date_purchased的订单表。我想编写一个SQL查询,对于表中的每一行,添加一个名为“repeat_order_count”的新字段,该字段显示此客户在订购此订单之前订购的次数。

例如,如果John在此订单之前订购了一次,则此订单的repeat_order_count将为2,换句话说,这是John订购的第二次。我遇到John的下一个订单行将有一个3,依此类推。这将允许我创建一个折线图,显示重复客户随时间推出的订单数量。我现在可以回到过去的特定时间,并计算出在此期间重复客户下了多少订单:

SELECT 
      * 
FROM orders 
WHERE repeat_order_count > 1 
WHERE date_purchased = January 2014 --(simplifying things here) 

我现在也能够确定客户何时成为重复客户。

我无法弄清楚要解决此问题的查询。或者可能有更简单的方法来做到这一点?

2 个答案:

答案 0 :(得分:0)

当您插入订单表时,对于您OrderCount的列,您使用了共同相关的子查询。 例如:

select
    col1,
    col2,
    (isnull((select count(*) from orders where custID = @currentCustomer),0) + 1),
    col4

请注意,处理第二个订单时,您不会添加该字段,该字段已经存在,您只需填充它。

答案 1 :(得分:0)

检索指定结果的一种方法是在SELECT列表中使用相关子查询。这假定客户标识符为customers_email_addressdate_purchasedDATETIMETIMESTAMP(或其他规范格式),并且没有相同的重复值客户(即客户没有两个或更多具有相同date_purchased值的订单。)

SELECT s.orders_id
     , s.customers_email_address
     , s.date_purchased 
     , ( SELECT COUNT(1)
           FROM orders p
          WHERE p.customers_email_address = s.customers_email_address
            AND p.date_purchased          < s.date_purchased
       ) AS previous_order_count
  FROM orders s
 ORDER
    BY s.customers_email_address
     , s.date_purchased

相关子查询将为&#34;第一个&#34;返回0。为客户订购,为#34;第二&#34;订购。如果您想在计数中包含当前订单,请将<比较运算符替换为<=运算符。

<强>后续

为了执行该查询,我们需要特别关注相关子查询的性能,因为这将针对表中的每一行执行。 (表中的一百万行意味着该查询执行了一百万次。)拥有合适的索引是至关重要的。

对于我的回答中的查询,我建议尝试这样的索引:

ON orders (customers_email_address, date_purchased, orders_id)

有了这个索引,我们期望EXPLAIN显示外部查询正在使用的索引,以满足ORDER BY(No&#34; Using filesort&#34 ;在Extra列中),并作为覆盖索引(不查找基础表中的页面,&#34;使用索引&#34;显示在Extra列中。)

我给出的答案只展示了一种方法。它也可以使用连接模式返回等效结果,例如:

SELECT s.orders_id
     , s.customers_email_address
     , s.date_purchased
     , COUNT(p.orders_id)
  FROM orders s
  JOIN orders p
    ON p.customers_email_address = s.customers_email_address
   AND p.date_purchased         <= s.date_purchased
 GROUP
    BY s.customers_email_address
     , s.date_purchased
     , s.orders_id
 ORDER
    BY s.customers_email_address
     , s.date_purchased
     , s.orders_id

(此查询基于评论中提供的一些其他信息,以前不可用:orders_idorders表中是唯一的。)

如果我们保证{&1 34}以前的orders_id&#34;订单小于先前订单的orders_id,那么就可以使用该列代替date_purchased列。我们想要一个合适的索引:

... ON orders (customers_email_address, orders_id, date_purchased)

注意:索引中列的顺序 important 。有了这个索引,我们可以做到:

SELECT s.orders_id
     , s.customers_email_address
     , s.date_purchased
     , COUNT(p.orders_id)
  FROM orders s
  JOIN orders p
    ON p.customers_email_address = s.customers_email_address
   AND p.orders_id              <= s.orders_id
 GROUP
    BY s.customers_email_address
     , s.orders_id
 ORDER
    BY s.customers_email_address
     , s.orders_id

同样,我们要查看EXPLAIN的输出,以验证索引是否用于连接操作和GROUP BY操作。

注意:使用内部联接,我们需要使用<=比较,因此我们至少得到一个匹配的行。如果我们想要只计算&#34;之前的&#34;我们可以从该结果中减去1。订单(不计算当前订单),或者我们可以使用带有<比较的外部联接操作,因此我们可以获得一个计数为0的行。