SQL 服务器每月查询新订单和重复订单
SQL Server query for new and repeat orders per month
我在 SQL Server 2008 R2 中工作,很难收集新客户订单和重复客户订单。
我有这种格式的数据:
OrderID OrderDate Customer OrderAmount
-----------------------------------------------
1 1/1/2017 A
2 1/2/2017 B
3 1/3/2017 C
4 4/1/2017 C
5 4/2/2017 D
6 4/3/2017 D
7 1/6/2018 B
这是我们想要的:
- 新定义为:客户在之前的任何月份都没有下过任何订单。
- 重复定义为:客户在前一个月下过订单(即使很多年前)。
这意味着,如果新客户在她的第一个月下了多个订单,这些订单都将被视为 "new" 个客户订单。随后几个月的订单都将被视为 "repeat" 个客户订单。
我们希望每年、每月获得新订单(计数和总和)和重复订单(计数和总和):
Year Month NewCount NewSum RepeatCount RepeatSum
-----------------------------------------------------------------------------
2017 1 3 (A,B,C) (10+20+30) 0 [=12=]
2017 4 2 (D,D) 0 (50+60) 1 (C) (40)
2018 1 0 [=12=] 1 (B) (70)
(() 括号中的信息不是结果的一部分;只是为了清楚起见而放在这里)
SQL 很容易写出任何一个给定的月份,但是当一次收集数年的月份时,我不知道该怎么做...
如果一个月没有任何订单,那么 year:month 的 NULL 或 0 值将是首选。
首先,首先汇总每个客户每月一条记录的数据。
然后,您可以使用自连接或类似构造来获取您需要的信息:
with cm as (
select customer, dateadd(day, 1 - day(orderdate), orderdate) as yyyymm
sum(orderamount) as monthamount, count(*) as numorders
from orders
group by customer
)
select year(cm.yyyymm) as yr, month(cm.yyyymm) as mon,
sum(case when cm.num_orders > 0 and cm_prev.customer is null then 1 else 0 end) as new_count,
sum(case when cm.num_orders > 0 and cm_prev.customer is null then monthamount else 0 end) as new_amount,
sum(case when cm.num_orders > 0 and cm_prev.customer > 0 then 1 else 0 end) as repeat_count,
sum(case when cm.num_orders > 0 and cm_prev.customer > 0 then monthamount else 0 end) as repeat_amount
from cm left join
cm cm_prev
on cm.customer = cm_prev.customer and
cm.yyyymm = dateadd(month, 1, cm_prev.yyyymm)
group by year(cm.yyyymm), month(cm.yyyymm)
order by year(cm.yyyymm), month(cm.yyyymm);
这在 SQL Server 2012 中会更容易一些,您可以在其中使用 lag()
.
您可以使用dense_rank
寻找新老客户。此查询 returns 您提供的输出
declare @t table (OrderID int, OrderDate date, Customer char(1), OrderAmount int)
insert into @t
values (1, '20170101', 'A', 10)
, (2, '20170102', 'B', 20), (3, '20170103', 'C', 30)
, (4, '20170401', 'C', 40), (5, '20170402', 'D', 50)
, (6, '20170403', 'D', 60), (7, '20180106', 'B', 70)
select
[year], [month], NewCount = isnull(sum(case when dr = 1 then 1 end), 0)
, NewSum = isnull(sum(case when dr = 1 then OrderAmount end), 0)
, RepeatCount = isnull(sum(case when dr > 1 then 1 end), 0)
, RepeatSum = isnull(sum(case when dr > 1 then OrderAmount end), 0)
from (
select
*, [year] = year(OrderDate), [month] = month(OrderDate)
, dr = dense_rank() over (partition by Customer order by dateadd(month, datediff(month, 0, OrderDate), 0))
from
@t
) t
group by [year], [month]
输出
year month NewCount NewSum RepeatCount RepeatSum
----------------------------------------------------------
2017 1 3 60 0 0
2018 1 0 0 1 70
2017 4 2 110 1 40
如果要显示没有订单的月份,必须首先获取table中的每一年与所有月份的组合。然后加入上层查询
select
*
from
(select distinct y = year(OrderDate) from @t) t
cross join (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) q(m)
我在 SQL Server 2008 R2 中工作,很难收集新客户订单和重复客户订单。
我有这种格式的数据:
OrderID OrderDate Customer OrderAmount
-----------------------------------------------
1 1/1/2017 A
2 1/2/2017 B
3 1/3/2017 C
4 4/1/2017 C
5 4/2/2017 D
6 4/3/2017 D
7 1/6/2018 B
这是我们想要的:
- 新定义为:客户在之前的任何月份都没有下过任何订单。
- 重复定义为:客户在前一个月下过订单(即使很多年前)。
这意味着,如果新客户在她的第一个月下了多个订单,这些订单都将被视为 "new" 个客户订单。随后几个月的订单都将被视为 "repeat" 个客户订单。
我们希望每年、每月获得新订单(计数和总和)和重复订单(计数和总和):
Year Month NewCount NewSum RepeatCount RepeatSum
-----------------------------------------------------------------------------
2017 1 3 (A,B,C) (10+20+30) 0 [=12=]
2017 4 2 (D,D) 0 (50+60) 1 (C) (40)
2018 1 0 [=12=] 1 (B) (70)
(() 括号中的信息不是结果的一部分;只是为了清楚起见而放在这里)
SQL 很容易写出任何一个给定的月份,但是当一次收集数年的月份时,我不知道该怎么做...
如果一个月没有任何订单,那么 year:month 的 NULL 或 0 值将是首选。
首先,首先汇总每个客户每月一条记录的数据。
然后,您可以使用自连接或类似构造来获取您需要的信息:
with cm as (
select customer, dateadd(day, 1 - day(orderdate), orderdate) as yyyymm
sum(orderamount) as monthamount, count(*) as numorders
from orders
group by customer
)
select year(cm.yyyymm) as yr, month(cm.yyyymm) as mon,
sum(case when cm.num_orders > 0 and cm_prev.customer is null then 1 else 0 end) as new_count,
sum(case when cm.num_orders > 0 and cm_prev.customer is null then monthamount else 0 end) as new_amount,
sum(case when cm.num_orders > 0 and cm_prev.customer > 0 then 1 else 0 end) as repeat_count,
sum(case when cm.num_orders > 0 and cm_prev.customer > 0 then monthamount else 0 end) as repeat_amount
from cm left join
cm cm_prev
on cm.customer = cm_prev.customer and
cm.yyyymm = dateadd(month, 1, cm_prev.yyyymm)
group by year(cm.yyyymm), month(cm.yyyymm)
order by year(cm.yyyymm), month(cm.yyyymm);
这在 SQL Server 2012 中会更容易一些,您可以在其中使用 lag()
.
您可以使用dense_rank
寻找新老客户。此查询 returns 您提供的输出
declare @t table (OrderID int, OrderDate date, Customer char(1), OrderAmount int)
insert into @t
values (1, '20170101', 'A', 10)
, (2, '20170102', 'B', 20), (3, '20170103', 'C', 30)
, (4, '20170401', 'C', 40), (5, '20170402', 'D', 50)
, (6, '20170403', 'D', 60), (7, '20180106', 'B', 70)
select
[year], [month], NewCount = isnull(sum(case when dr = 1 then 1 end), 0)
, NewSum = isnull(sum(case when dr = 1 then OrderAmount end), 0)
, RepeatCount = isnull(sum(case when dr > 1 then 1 end), 0)
, RepeatSum = isnull(sum(case when dr > 1 then OrderAmount end), 0)
from (
select
*, [year] = year(OrderDate), [month] = month(OrderDate)
, dr = dense_rank() over (partition by Customer order by dateadd(month, datediff(month, 0, OrderDate), 0))
from
@t
) t
group by [year], [month]
输出
year month NewCount NewSum RepeatCount RepeatSum
----------------------------------------------------------
2017 1 3 60 0 0
2018 1 0 0 1 70
2017 4 2 110 1 40
如果要显示没有订单的月份,必须首先获取table中的每一年与所有月份的组合。然后加入上层查询
select
*
from
(select distinct y = year(OrderDate) from @t) t
cross join (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12)) q(m)