我有一个包含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)
我现在也能够确定客户何时成为重复客户。
我无法弄清楚要解决此问题的查询。或者可能有更简单的方法来做到这一点?
答案 0 :(得分:0)
当您插入订单表时,对于您OrderCount
的列,您使用了共同相关的子查询。
例如:
select
col1,
col2,
(isnull((select count(*) from orders where custID = @currentCustomer),0) + 1),
col4
请注意,处理第二个订单时,您不会添加该字段,该字段已经存在,您只需填充它。
答案 1 :(得分:0)
检索指定结果的一种方法是在SELECT列表中使用相关子查询。这假定客户标识符为customers_email_address
,date_purchased
为DATETIME
或TIMESTAMP
(或其他规范格式),并且没有相同的重复值客户(即客户没有两个或更多具有相同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_id
在orders
表中是唯一的。)
如果我们保证{&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的行。