在当月销售前滚动前13个月

时间:2014-04-18 17:40:59

标签: sql-server

在SQL Server 2012数据库中,我有一个包含两列customeriddate的表。我有兴趣按月购买本月购买但未过去13个月的客户数量。桌子非常大,所以高效率的东西将受到高度赞赏。结果表显示在输入数据之后。从本质上讲,它是在当月购买但未在之前的13个月(按年和月)购买的客户数。

---输入表-----

declare @Sales as Table ( customerid Int, date Date );
insert into @Sales ( customerid, date) values
  ( 1, '01/01/2012' ),  
  ( 1, '04/01/2013' ),  
  ( 1, '01/01/2014' ),  
  ( 1, '01/01/2014' ),  
  ( 1, '04/06/2014' ),  
  ( 2, '04/01/2014' ),  
  ( 3, '01/03/2012' ),  
  ( 3, '01/03/2014' ),  
  ( 4, '01/04/2012' ),  
  ( 4, '04/04/2013' ),  
  ( 5, '02/01/2010' ),  
  ( 5, '02/01/2013' ),  
  ( 5, '04/01/2014' )      
    select  customerid, date
      from @Sales;

---期望的结果----

yearmth monthpurchasers monthpurchasernot13m
201002 1 1 201201 3 3
201302 1 1
201304 2 2
201401 2 1
201404 3 2
非常感谢你看到这个!

开发

3 个答案:

答案 0 :(得分:1)

你没有提供预期的结果,但我相信这非常接近(至少在逻辑上):

;with g as (
    select customerid, year(date)*100 + month(date) as mon
    from @Sales 
    group by customerid, year(date)*100 + month(date) 
),
x as (
    select *,
        count(*) over(partition by customerid order by mon
            rows between 13 preceding and 1 preceding) as cnt
    from g
),
y as (
    select mon, count(*) as cnt from x
    where cnt = 0
    group by mon
)
select g.mon,
    count(distinct(g.customerid)) as monthpurchasers,
    isnull(y.cnt, 0) as cnt
from g
left join y on g.mon = y.mon
group by g.mon, y.cnt
order by g.mon

答案 1 :(得分:0)

以下查询将生成您要查找的内容。我不确定在一张大桌子上表现如何(你的桌子有多大?)但它非常直接,所以我认为它会好的。我只是计算13个月前的CTE来找到我的销售窗口。然后加入该窗口/客户ID中的Sales表,并根据不匹配的记录对记录进行分组。你实际上并不需要2个CTE,你可以在第二个CTE的连接部分做DATEADD(mm,-13,date),但我认为这样可能会更清楚。

P.S。如果您需要将时间范围从13个月更改为其他内容,则必须更改的是DATEADD(mm,-13,date),这样可以从日期值中减去13个月。

希望这有助于或至少带来更好的解决方案

;WITH PurchaseWindow AS (
select  customerid, date, DATEADD(mm,-13,date) minsaledate
FROM @Sales
), JoinBySaleWindow AS (
SELECT a.customerid, a.date,a.minsaledate,b.date earliersaledate
FROM PurchaseWindow a
    LEFT JOIN @sales b ON a.customerid =b.customerid 
        --Find the sales for the customer within the last 13 months of original sale
        AND b.date BETWEEN a.date AND a.minsaledate
)
SELECT DATEPART(yy,date) AS [year], DATEPART(mm, date) AS [month], COUNT(DISTINCT customerid) monthpurchases
FROM JoinBySaleWindow
--Exclude records where a sale within last 13 months occured
WHERE earliersaledate IS NULL
GROUP BY DATEPART(mm, date), DATEPART(yy,date)

对于他们现在修复的拼写错误感到抱歉。

答案 2 :(得分:0)

告诉我此查询是否有帮助。它将满足您条件的所有行提取到Table变量中。然后,我使用您的查询并加入此表。

declare @startDate datetime
declare @todayDate datetime
declare @tbl_Custs as Table(customerid int)
set @startDate = '04/01/2014' -- mm/dd/yyyy
set @todayDate = GETDATE()
insert into @tbl_Custs
-- purchased only this month
select customerid
from Sales
where ([date] >= @startDate and [date] <= @todayDate)
and customerid NOT in 
(
-- purchased in past 13 months 
select distinct customerid 
from Sales 
where ([date] >= DATEADD(MONTH,-13,[date]) 
and [date] < @startDate)
) 
-- your query goes here
select year(date) as year
    ,month(date) as month
    ,count(distinct(c.customerid)) as monthpurchasers
from @tbl_Custs as c right join
Sales as s
on c.customerid = s.customerid
group by year(date) , month(date) 
order by year(date) , month(date)