首次下订单时获取日期和唯一客户数

Posted

技术标签:

【中文标题】首次下订单时获取日期和唯一客户数【英文标题】:Getting date, and count of unique customers when first order was placed 【发布时间】:2019-10-27 14:20:27 【问题描述】:

我有一个名为 orders 的表,如下所示:

+--------------+---------+------+-----+---------+-------+
| Field        | Type    | Null | Key | Default | Extra |
+--------------+---------+------+-----+---------+-------+
| id           | int(11) | YES  |     | NULL    |       |
| memberid     | int(11) | YES  |     | NULL    |       |
| deliverydate | date    | YES  |     | NULL    |       |
+--------------+---------+------+-----+---------+-------+

其中包含以下数据:

+------+----------+--------------+
| id   | memberid | deliverydate |
+------+----------+--------------+
|    1 |      991 | 2019-10-25   |
|    2 |      991 | 2019-10-26   |
|    3 |      992 | 2019-10-25   |
|    4 |      992 | 2019-10-25   |
|    5 |      993 | 2019-10-24   |
|    7 |      994 | 2019-10-21   |
|    6 |      994 | 2019-10-26   |
|    8 |      995 | 2019-10-26   |
+------+----------+--------------+

我想要一个返回每个唯一日期的结果集,以及一个单独的列,显示当天有多少客户下了他们的第一个订单。

我在以正确方式查询时遇到问题,尤其是当数据包含同一客户同一天的多个订单时。

我的方法是

    获取在我要查看的时间段内下订单的所有唯一会员 ID 通过比较该时间段前下单的memberid,过滤掉该时间段内首次下单的会员 按交货日期分组,并计算所有唯一的 memberid(但这显然每天单独计算唯一的 memberid!)

下面是对应的SQL:

SELECT deliverydate,COUNT(DISTINCT memberid) FROM orders
WHERE 
    MemberId IN (SELECT DISTINCT memberid FROM orders WHERE deliverydate BETWEEN '2019-10-25' AND '2019-10-26')
AND NOT 
    MemberId In (SELECT DISTINCT memberid FROM orders WHERE deliverydate < '2019-10-25')
GROUP BY deliverydate
ORDER BY deliverydate ASC;

但这会导致上述数据如下:

+--------------+--------------------------+
| deliverydate | COUNT(DISTINCT memberid) |
+--------------+--------------------------+
| 2019-10-25   |                        2 |
| 2019-10-26   |                        2 |
+--------------+--------------------------+

2019-10-26 的计数应该是 1。

感谢任何帮助:)

【问题讨论】:

【参考方案1】:

你可以聚合两次:

select first_deliverydate, count(*) cnt
from (
    select min(deliverydate) first_deliverydate
    from orders
    group by memberid
) t
group by first_deliverydate
order by first_deliverydate

子查询为您提供每个成员的第一个订单数据,然后外部查询按第一个订单日期聚合和计数。

demo on DB Fiddle 与您的示例数据返回:

first_deliverydate | cnt :----------------- | --: 2019-10-21 | 1 2019-10-24 | 1 2019-10-25 | 2 2019-10-26 | 1

mysql 8.0 中,这也可以通过窗口函数来实现:

select deliverydate first_deliverydate, count(*) cnt
from (
    select deliverydate, row_number() over(partition by memberid order by deliverydate) rn
    from orders
) t
where rn = 1
group by deliverydate
order by deliverydate

Demo on DB Fiddle

【讨论】:

【参考方案2】:

您必须首先弄清楚第一个交货日期是什么时候:

SELECT firstdeliverydate,COUNT(DISTINCT memberid) FROM (
select memberid, min(deliverydate) as firstdeliverydate
from orders
WHERE 
    MemberId IN (SELECT DISTINCT memberid FROM orders WHERE deliverydate BETWEEN '2019-10-25' AND '2019-10-26')
AND NOT 
    MemberId In (SELECT DISTINCT memberid FROM orders WHERE deliverydate < '2019-10-25')
group by memberid)
t1
group by firstdeliverydate

【讨论】:

【参考方案3】:

使用NOT EXISTS 获取每个客户的第一个订单,然后使用GROUP BY deliverydate 计算下订单的不同客户:

select o.deliverydate, count(distinct o.memberid) counter
from orders o
where not exists (
  select 1 from orders
  where memberid = o.memberid and deliverydate < o.deliverydate
)  
group by o.deliverydate

请参阅demo。 结果:

| deliverydate        | counter |
| ------------------- | ------- |
| 2019-10-21 00:00:00 | 1       |
| 2019-10-24 00:00:00 | 1       |
| 2019-10-25 00:00:00 | 2       |
| 2019-10-26 00:00:00 | 1       |

但是,如果您想要表格中所有日期的结果,包括那些没有新客户订单的日期(所以计数器将是 0):

select d.deliverydate, count(distinct o.memberid) counter
from (
  select distinct deliverydate  
  from orders
) d left join orders o
on o.deliverydate = d.deliverydate and not exists (
  select 1 from orders
  where memberid = o.memberid and deliverydate < o.deliverydate
)  
group by d.deliverydate

【讨论】:

以上是关于首次下订单时获取日期和唯一客户数的主要内容,如果未能解决你的问题,请参考以下文章

根据日期和请求数创建唯一 ID

SQL 获取超过某个日期的记录,高于某个值,最小数量

LeetCode:Database 64.即时食物配送 II

WooCommerce Rest Api:按特定日期获取订单

获取按月顺序显示的特定日期之间的所有订单

如何在codeigniter中按日期降序获取订单