【问题标题】:Repeat Customers Each Year (Retention)每年的回头客(保留)
【发布时间】:2013-06-28 15:30:44
【问题描述】:

我一直在努力,但我认为我做得不对。 |D

我们的数据库无法跟踪我们保留了多少客户,因此我们寻找了一种替代方法。它概述了in this article。它建议您填写此表:

Year  Number of Customers   Number of customers Retained in 2009    Percent (%) Retained in 2009    Number of customers Retained in 2010    Percent (%) Retained in 2010  ....

2008
2009
2010
2011
2012
Total

表格将在标题中显示为 2012 年。我只是在节省空间。

它告诉您查找您在开始年度拥有的客户总数。为此,我使用了这个查询,因为我们的起始年份是 2008 年:

select YEAR(OrderDate) as 'Year', COUNT(distinct(billemail)) as Customers
from dbo.tblOrder
where OrderDate >= '2008-01-01' and OrderDate <= '2008-12-31'
group by YEAR(OrderDate)

目前我们只是通过电子邮件地址来区分我们的客户。

然后您必须搜索在以后几年(我们是 2009 年、10 年、11 年和 12 年)再次购买的同名客户

我想出了这个。它应该会找到在 2008 年和 2009 年购买的人。

SELECT YEAR(OrderDate) as 'Year',COUNT(distinct(billemail)) as Customers
FROM dbo.tblOrder o with (nolock)
WHERE o.BillEmail IN (SELECT DISTINCT o1.BillEmail 
        FROM dbo.tblOrder o1 with (nolock)
        WHERE o1.OrderDate BETWEEN '2008-1-1' AND '2009-1-1')
    AND o.BillEmail IN (SELECT DISTINCT o2.BillEmail 
        FROM dbo.tblOrder o2 with (nolock)
        WHERE o2.OrderDate BETWEEN '2009-1-1' AND '2010-1-1')
    --AND o.OrderDate BETWEEN '2008-1-1' AND '2013-1-1' 
    AND o.BillEmail NOT LIKE '%@halloweencostumes.com'
    AND o.BillEmail NOT LIKE ''
GROUP BY YEAR(OrderDate)

所以我只是找到在这两年购买的客户。然后我做一个独立的查询来查找那些在 2008 年和 2010 年购买的人,然后是 08 和 11 年,然后是 08 和 12 年。这个找到了 2008 年和 2010 年的购买者:

SELECT YEAR(OrderDate) as 'Year',COUNT(distinct(billemail)) as Customers
FROM dbo.tblOrder o with (nolock)
WHERE o.BillEmail IN (SELECT DISTINCT o1.BillEmail 
        FROM dbo.tblOrder o1 with (nolock)
        WHERE o1.OrderDate BETWEEN '2008-1-1' AND '2009-1-1')
    AND o.BillEmail IN (SELECT DISTINCT o2.BillEmail 
        FROM dbo.tblOrder o2 with (nolock)
        WHERE o2.OrderDate BETWEEN '2010-1-1' AND '2011-1-1')
    --AND o.OrderDate BETWEEN '2008-1-1' AND '2013-1-1' 
    AND o.BillEmail NOT LIKE '%@halloweencostumes.com'
    AND o.BillEmail NOT LIKE ''
GROUP BY YEAR(OrderDate)

所以你看我对每年的比较都有不同的查询。他们都是无关的。所以最后我只是找到在 2008 年和 2009 年购买的人,然后是在 2008 年和 2010 年购买的可能不同的群体,依此类推。为了准确起见,我是否每次都必须使用相同的 2008 年买家分组?所以他们在 2009 年和 2010 年和 2011 年和 2012 年购买了?

这就是我担心的地方,不知道如何继续甚至找到此类数据。

任何建议将不胜感激!谢谢!

【问题讨论】:

  • 如果存在差距,您如何考虑留存率,例如 2008 年 12 月 28 日订购的人 - 然后在 2009 年什么都没有,但在 2010 年 1 月 2 日再次订购。您希望这些数字代表什么在保留日志中。

标签: sql sql-server sql-server-2008


【解决方案1】:

基于每个客户的交叉表如何帮助您...

由此,您可以通过比较客户的 从当前年份到上一个年份,并有每个相应年份的总客户数。 从中您可以在最终输出中运行您想要的任何百分比

这应该会为您提供所有相关年份的完整集合,并且您可以根据需要继续添加年份以进行比较。它应该非常快,尤其是如果您在 (BillEMail, OrderDate) 上有一个索引。

前提是内部查询只是遍历所有记录,如果在给定年份内有任何订单(通过 MAX()),则基于客户将标志设置为 1。它通过 case/when 每年为客户检测到。一旦确定了这一点,外部查询就会将每个客户与他们在一年内是否有销售与前一年进行比较,如果是,则 SUM() 1 与 0 进行比较,然后您就有了留存率。

SELECT
      SUM( case when PreQry.C2011 = 1 and PreQry.C2012 = 1 then 1 else 0 end ) as Retain2011_2012,
      SUM( case when PreQry.C2010 = 1 and PreQry.C2011 = 1 then 1 else 0 end ) as Retain2010_2011,
      SUM( case when PreQry.C2009 = 1 and PreQry.C2010 = 1 then 1 else 0 end ) as Retain2009_2010,
      SUM( case when PreQry.C2008 = 1 and PreQry.C2009 = 1 then 1 else 0 end ) as Retain2008_2009,
      SUM( PreQry.C2012 ) CustCount2012,
      SUM( PreQry.C2011 ) CustCount2011,
      SUM( PreQry.C2010 ) CustCount2010,
      SUM( PreQry.C2009 ) CustCount2009,
      SUM( PreQry.C2008 ) CustCount2008
   from 
      ( select 
              O.BillEMail as customer,
              MAX( CASE when YEAR( O.OrderDate ) = 2012 then 1 else 0 end ) as C2012, 
              MAX( CASE when YEAR( O.OrderDate ) = 2011 then 1 else 0 end ) as C2011, 
              MAX( CASE when YEAR( O.OrderDate ) = 2010 then 1 else 0 end ) as C2010, 
              MAX( CASE when YEAR( O.OrderDate ) = 2009 then 1 else 0 end ) as C2009, 
              MAX( CASE when YEAR( O.OrderDate ) = 2008 then 1 else 0 end ) as C2008
           from 
              dbo.tblOrder O
           where 
                  O.OrderDate >= '2008-01-01' 
              AND O.BillEmail NOT LIKE '%@halloweencostumes.com'
              AND O.BillEmail NOT LIKE ''
           group by 
              O.BillEMail ) as PreQry

现在,如果您想检测给定年份有多少是“新”,您可以添加其他列,例如测试上一年的销售标志 = 0 与当前年份 = 1,例如

SUM( case when PreQry.C2011 = 0 and PreQry.C2012 = 1 then 1 else 0 end ) as NewIn2012,
SUM( case when PreQry.C2010 = 0 and PreQry.C2011 = 1 then 1 else 0 end ) as NewIn2011,
SUM( case when PreQry.C2009 = 0 and PreQry.C2010 = 1 then 1 else 0 end ) as NewIn2010,
SUM( case when PreQry.C2008 = 0 and PreQry.C2009 = 1 then 1 else 0 end ) as NewIn2009

【讨论】:

  • 您的数字实际上与我的相符,但您的操作效率更高,手动步骤更少。帮我学习,哈哈。谢谢!
  • @spazzie,这能解决你的问题吗?或者我是否遗漏了其他东西......这个版本是相应数据的所有列的一行,无论输出格式是什么,简单的划分都应该是简单的而不是 UNPIVOTing。
  • 我喜欢这个主意。您基本上是在对每个客户进行交叉制表,其中的列是他们下订单的年份。它也更灵活,让您有更好的机会回答随机的“假设”问题。唯一的缺点是每年都需要具体定义。但这可以通过简单地添加到 2020 年或其他时间的字段来解决。
  • 很棒的快速解决方案。应该注意的是,客户可以在 12 月 31 日和 1 月 1 日订购并被视为保留客户。在订单之间滚动 12 个月是理想的,但我什么都没有……
【解决方案2】:

如果我对您的问题的理解正确,那么您听起来好像在细节上搞混了。这取决于您希望您对“保留”的定义是什么。 “前几年也买过”怎么样?然后,对于 X 年,如果客户在前一年也从您那里购买过产品,那么他们将被保留。

以 2012 年为例:

SELECT YEAR(OrderDate) as 'Year',COUNT(distinct(billemail)) as Customers
FROM dbo.tblOrder o with (nolock)
WHERE o.BillEmail IN (SELECT DISTINCT o1.BillEmail 
        FROM dbo.tblOrder o1 with (nolock)
        WHERE o1.OrderDate BETWEEN '2012-1-1' AND '2013-1-1')
    AND o.BillEmail IN (SELECT DISTINCT o2.BillEmail 
        FROM dbo.tblOrder o2 with (nolock)
        WHERE o2.OrderDate < '2012-1-1')
    AND o.BillEmail NOT LIKE '%@halloweencostumes.com'
    AND o.BillEmail NOT LIKE ''
GROUP BY YEAR(OrderDate)

这行得通吗?

编辑

您可以更进一步,将年份抽象出来,这样 1 个查询就足够了:

SELECT YEAR(O.OrderDate) as 'Year',COUNT(distinct(billemail)) as Customers
FROM dbo.tblOrder o with (nolock)
WHERE o.BillEmail IN (SELECT DISTINCT o1.BillEmail 
        FROM dbo.tblOrder o1 with (nolock)
        WHERE year(o1.OrderDate)=YEAR(O.OrderDate)
    AND o.BillEmail IN (SELECT DISTINCT o2.BillEmail 
        FROM dbo.tblOrder o2 with (nolock)
        WHERE year(o2.OrderDate) < year(o.orderdate)
    AND o.BillEmail NOT LIKE '%@halloweencostumes.com'
    AND o.BillEmail NOT LIKE ''
GROUP BY YEAR(OrderDate)

这应该为您提供您有订单的每一年的不同客户数量,以及在前一年购买的客户数量。但是,它与您要填充的表格的格式不同。

【讨论】:

  • 我正在尝试按照链接到的文章中的说明进行操作,但由于某种原因我一直搞混了。但是,您的查询不会返回任何数据。不过谢谢!
  • 修复了问题。我在第一个子查询中使用了 2012 两次。
  • 好的,它现在正在拉东西!这显示了 2012 年和前一年购买的人数?
  • 是的。另请参阅我的 EDIT,其中我扩展了概念,因此您只需运行 1 个查询,而不是每年运行一个。
猜你喜欢
  • 2021-02-02
  • 1970-01-01
  • 2023-02-08
  • 2017-11-09
  • 1970-01-01
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多