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)