按财务年度分组并将这些组应用为过滤器

时间:2010-08-09 10:35:46

标签: sql sql-server sql-server-2005

我希望建立6个客户群的小组:

非购买者(从未向我们购买)
新购买者(本财政年度内首次购买)
重新激活的购买者(在当前财政年度购买,也在最近的第二年购买)
失效购买者(在上一个财政年度购买但不是当前购买者)
2年连续购买者(已在本财政年度购买,最近一次购买)
3-4岁的连续购买者(过去3或4个财政年度每年购买)
5年以上的连续购买者(每个财政年度购买至少5年)

我将使用的财政年度将从4月1日到3月31日,并将使用下表:

purchaser (including id (primary key))

purchases (date_purchased, purchases_purchaser_id)

如果表格在purchaser_id = purchases_purchaser_id上加入,并且每个购买者可以在任何财政年度内进行多次购买(因此可能按年份分组)

这让我很生气,所以任何帮助都会受到重视!

谢谢, 达文

3 个答案:

答案 0 :(得分:2)

这是动态版

Declare @currentYear int
Declare @OlderThan5yrs datetime 

Set @currentYear  = Year(GetDate()) - Case When month(GetDate())<4 then 1 else 0 end
Set @OlderThan5yrs = cast(cast( @currentYear-5 as varchar(4))+'/04/01' as datetime)

Select p.pName,
       p.purchaser_id,
       isNull(a.[5+YrAgo],0) as [5+YrAgo],
       isNull(a.[4YrAgo], 0)  as [4YrAgo],
       isNull(a.[3YrAgo], 0)  as [3YrAgo],
       isNull(a.[2YrAgo], 0)  as [2YrAgo],
       isNull(a.[1YrAgo], 0)  as [1YrAgo],
       isNull(a.[CurYr],  0)   as [CurYr],
       isNull(a.Category, 'Non-purchaser (ever)') as Category
From purchasers p
Left Join 
(        
   Select purchases_purchaser_id, 
          [5] as [5+YrAgo],
          [4] as [4YrAgo],
          [3] as [3YrAgo],
          [2] as [2YrAgo],
          [1] as [1YrAgo],
          [0]  as [CurYr],
         Case When [4]+[3]+[2]+[1]+[0] = 5     Then '5+ year consecutive'
              When [2]+[1]+[0] = 3             Then '3-4 yr consecutive'
              When [1]+[0] = 2                 Then '2 yr Consecutive'
              When [1]=1 and [0]=0             Then 'Lapsed'
              When [2]=1 and [1]=0 and [0]=1   Then 'Reactivated'
              When [4]+[3]+[2]+[1]=0 and [0]=1 Then 'New'
              When [4]+[3]+[2]+[1]+[0] = 0     Then 'Non-purchaser (last 5 yrs)'
              Else 'non categorized'
         End as Category     
   From (
            Select purchases_purchaser_id, 
                   Case When date_purchased < @OlderThan5yrs Then 5 
                        Else @currentYear - Year(date_purchased)+ Case When month(date_purchased)<4 Then 1 else 0 end 
                     end as fiscalYear, count(*) as nPurchases
            From purchases 
            Group by purchases_purchaser_id,
                   Case When date_purchased < @OlderThan5yrs Then 5 
                        Else @currentYear - Year(date_purchased)+ Case When month(date_purchased)<4 Then 1 else 0 end 
                     end
         ) as AggData
   PIVOT ( count(nPurchases) for fiscalYear in ([5],[4],[3],[2],[1],[0]) ) pvt
) as a
on p.purchaser_id=a.purchases_purchaser_id

<强>更新:

这是我在先前查询中插入数据的结果(您必须在查询中添加#表名)。

pName                purchaser_id 5+YrAgo 4YrAgo 3YrAgo 2YrAgo 1YrAgo CurYr Category
-------------------- ------------ ------- ------ ------ ------ ------ ----- --------------------------
Non-purchaser                   0       0      0      0      0      0     0 Non-purchaser (ever)
New purchaser                   1       0      0      0      0      0     1 New
Reactivated                     2       0      0      1      1      0     1 Reactivated
Lapsed                          3       0      0      0      1      1     0 Lapsed
2 yr Consecutive                4       0      0      0      0      1     1 2 yr Consecutive
3 yr consecutive                5       0      0      0      1      1     1 3-4 yr consecutive
4 yr consecutive                6       0      0      1      1      1     1 3-4 yr consecutive
5+ year consecutive             7       1      1      1      1      1     1 5+ year consecutive
Uncategorized                   8       0      0      1      0      0     0 non categorized
old one                         9       1      0      0      0      0     0 Non-purchaser (last 5 yrs)

您也不需要列[5 + YrAgo],[4YrAgo],[3YrAgo],[2YrAgo],[1YrAgo]和[CurYr]。 我添加它们以便更容易检查查询逻辑。

更新2

以下是您在评论中询问的查询。 注意 我在查询中使用的表结构是:

Table purchasers ( purchaser_id int, pName varchar(20))
Table purchases (purchases_purchaser_id int, date_purchased datetime)

并且购买时有外键(purchases_purchaser_id)引用购买(purchaser_id)。

;With AggData as (
Select   purchases_purchaser_id, 
         Case When [4]+[3]+[2]+[1]+[0] = 5     Then 1 end as [Consec5],
         Case When [4]=0 and [2]+[1]+[0] = 3   Then 1 end as [Consec34],
         Case When [2]=0 and [1]+[0] = 2       Then 1 end as [Consec2],
         Case When [1]=1 and [0]=0             Then 1 end as [Lapsed],
         Case When [2]=1 and [1]=0 and [0]=1   Then 1 end as [Reactivated],
         Case When [4]+[3]+[2]+[1]=0 and [0]=1 Then 1 end as [New],
         Case When [4]+[3]+[2]>0 and [1]+[0]=0 Then 1 end as [Uncateg]
   From  (
            Select purchases_purchaser_id, 
                   @currentYear - Year(date_purchased) + Case When month(date_purchased)<4 Then 1 else 0 end as fiscalYear, 
                   count(*) as nPurchases
              From purchases      
             Where date_purchased >= @OlderThan5yrs  
             Group by purchases_purchaser_id,
                      @currentYear - Year(date_purchased) + Case When month(date_purchased)<4 Then 1 else 0 end
         ) as AggData
   PIVOT ( count(nPurchases) for fiscalYear in ([4],[3],[2],[1],[0]) ) pvt
)
Select count([Consec5])     as [Consec5],
       count([Consec34])    as [Consec34],
       count([Consec2])     as [Consec2],
       count([Lapsed])      as [Lapsed],
       count([Reactivated]) as [Reactivated],
       count([New])         as [New],
       count(*)-count(a.purchases_purchaser_id) as [Non],
       count([Uncateg])     as [Uncateg]
  From purchasers p
 Left Join AggData as a
  on p.purchaser_id=a.purchases_purchaser_id              

结果(使用上一篇文章中的测试数据)

Consec5 Consec34 Consec2 Lapsed Reactivated New Non Uncateg
------- -------- ------- ------ ----------- --- --- -------
      1        2       1      1           1   1   2       1

答案 1 :(得分:1)

虽然使用另一个显示5个会计年度的日期范围表可以更轻松地完成,但我已经为您的查询硬编码了来自/到日期的参考资料并且似乎正在运作...

INNER Select将根据给定日期范围内的任何一次或多次购买预先收集“旗帜”...例如:2010年4月1日=“20100401”,日期转换为2011年3月31日=“20110331 “,并且在过去的5年中循环...此外,在实际购买表中购买日期以确定”从未购买“与购买6,7或更早年历史的人的任意数据......

查询的基础将基本上创建一个活动发生的可能个别年份的交叉表。然后我可以用最详细的标准查询他们的分类标题,至少......

我尽可能地从另一种SQL语言转换为符合SQL-Server语法(主要是关于日期转换),但除此之外,原则和查询都有效...最终的分类列是字符,但可以是无论你想取代什么。

SELECT
      id,
      CASE 
         WHEN year1 + year2 + year3 + year4 + year5 = 5 THEN "5+yrs "
         WHEN year1 + year2 + year3 + year4 >= 3 THEN "3-4yrs"
         WHEN year1 + year2 = 2, "2yrs  "
         WHEN year1 = 1 AND year2 = 0 AND year3 = 1 THEN "Reacti"
         WHEN year1 = 1 THEN "New   "
         WHEN year1 = 0 AND year2 = 1 THEN "Lapsed"
         WHEN AnyPurchase = 1, "over5"
         ELSE "never" BuyerClassification
      END
   FROM
      ( SELECT
            id,
            MAX( CASE WHEN date_purchased >= CONVERT( Date, "20100401", 112 ) 
                       AND date_purchased <= CONVERT( Date, "20110331", 112 ) 
                 THEN 1 ELSE 0 END ) Year1,
            MAX( CASE WHEN date_purchased >= CONVERT( Date, "20090401", 112 ) 
                       AND date_purchased <= CONVERT( Date, "20100331", 112 )
                 THEN 1 ELSE 0 END ) Year2,
            MAX( CASE WEHEN date_purchased >= CONVERT( Date, "20080401", 112 ) 
                       AND date_purchased <= CONVERT( Date, "20090331", 112 )
                 THEN 1 ELSE 0 END ) Year3,
            MAX( CASE WHEN date_purchased >= CONVERT( Date, "20070401", 112 ) 
                       AND date_purchased <= CONVERT( Date, "20080331", 112 )
                 THEN 1 ELSE 0 END ) Year4,
            MAX( CASE WHEN date_purchased >= CONVERT( Date, "20060401", 112 ) 
                       AND date_purchased <= CONVERT( Date, "20070331", 112 )
                 THEN 1 ELSE 0 END ) Year5,
            MAX( CASE WHEN date_purchased <= CONVERT( Date, "20100401", 112 )
                 THEN 1 ELSE 0 END ) AnyPurchase
         FROM
            purchaser LEFT OUTER JOIN purchases
               ON purchaser.id = purchases.purchases_purchaser_id
         GROUP BY 
            1 ) PreGroup1

编辑 - 通过语法转换修复了parens并错过了它...

“分组1”是指通过查询中的第一列进行分组,该分组是来自购买者的购买者ID。通过左外连接将保证购买者表中的所有可能的人,无论是否有任何实际购买。 “PreGroup1”是select语句的“别名”,以防你想在最外面的select中进行其他连接,检测年份值进行分类。

尽管它可以正常工作,但可能不如其他人通过对查询进行分析所做的那样有效,但它可能会让您开始思考一些查询和聚合技术。这个过程基本上是通过在内部SQL-Select上使用case / when构造创建一个交叉表,并在OUTER中使用大多数SQL-Select进行最终分类。

答案 2 :(得分:1)

MS SQL Server(适用于2000,2005,2008)

SET NOCOUNT ON

CREATE TABLE #purchasers (purchaser_id int, pName varchar(20))

Insert Into #purchasers values (0, 'Non-purchaser')
Insert Into #purchasers values (1, 'New purchaser')
Insert Into #purchasers values (2, 'Reactivated')
Insert Into #purchasers values (3, 'Lapsed')
Insert Into #purchasers values (4, '2 yr Consecutive')
Insert Into #purchasers values (5, '3 yr consecutive')
Insert Into #purchasers values (6, '4 yr consecutive')
Insert Into #purchasers values (7, '5+ year consecutive')
Insert Into #purchasers values (8, 'Uncategorized')
Insert Into #purchasers values (9, 'old one')


CREATE TABLE #purchases (date_purchased datetime, purchases_purchaser_id int)

Insert Into #purchases values ('2010/05/03', 1)

Insert Into #purchases values ('2007/05/03', 2)
Insert Into #purchases values ('2008/05/03', 2)
Insert Into #purchases values ('2010/05/03', 2)

Insert Into #purchases values ('2008/05/03', 3)
Insert Into #purchases values ('2009/05/03', 3)


Insert Into #purchases values ('2009/05/03', 4)
Insert Into #purchases values ('2010/05/03', 4)

Insert Into #purchases values ('2008/05/03', 5)
Insert Into #purchases values ('2009/05/03', 5)
Insert Into #purchases values ('2010/05/03', 5)

Insert Into #purchases values ('2007/05/03', 6)
Insert Into #purchases values ('2008/05/03', 6)
Insert Into #purchases values ('2009/05/03', 6)
Insert Into #purchases values ('2010/05/03', 6)

Insert Into #purchases values ('2004/05/03', 7)
Insert Into #purchases values ('2005/05/03', 7)
Insert Into #purchases values ('2006/05/03', 7)
Insert Into #purchases values ('2007/05/03', 7)
Insert Into #purchases values ('2008/05/03', 7)
Insert Into #purchases values ('2009/05/03', 7)
Insert Into #purchases values ('2009/05/03', 7)
Insert Into #purchases values ('2009/05/03', 7)
Insert Into #purchases values ('2010/05/03', 7)

Insert Into #purchases values ('2007/05/03', 8)

Insert Into #purchases values ('2000/05/03', 9)

Select p.pName,
       p.purchaser_id,
       isNull(a.[2005],0) as [Bef.2006],
       isNull(a.[2006],0) as [2006],
       isNull(a.[2007],0) as [2007],
       isNull(a.[2008],0) as [2008],
       isNull(a.[2009],0) as [2009],
       isNull(a.[2010],0) as [2010],
       isNull(a.Category, 'Non-purchaser') as Category
From #purchasers p
Left Join 
(        
   Select purchases_purchaser_id, [2005],[2006],[2007],[2008],[2009],[2010],
         Case When [2006]+[2007]+[2008]+[2009]+[2010] = 5 Then '5+ year consecutive'
              When [2008]+[2009]+[2010] = 3               Then '3-4 yr consecutive'
              When [2009]+[2010] = 2                      Then '2 yr Consecutive'
              When [2009]=1 and [2010]=0                  Then 'Lapsed'
              When [2008]=1 and [2009]=0 and [2010]=1     Then 'Reactivated'
              When [2006]+[2007]+[2008]+[2009]=0 and [2010]=1 Then 'New'
              When [2006]+[2007]+[2008]+[2009]+[2010] = 0 Then 'Non-purchaser in last 5 yrs'
              Else 'non categorized'
         End as Category     
   From (
            Select purchases_purchaser_id, 
                   Case When date_purchased < '2006/04/01' Then 2005 
                        Else Year(date_purchased)- Case When month(date_purchased)<4 Then -1 else 0 end 
                     end as fiscalYear, count(*) as nPurchases
            From #purchases 
            Group by purchases_purchaser_id,
                     Case When date_purchased < '2006/04/01' Then 2005 
                        Else Year(date_purchased)- Case When month(date_purchased)<4 Then -1 else 0 end 
                     end
         ) as AggData
   PIVOT ( count(nPurchases) for fiscalYear in ([2005],[2006],[2007],[2008],[2009],[2010]) ) pvt
) as a
on p.purchaser_id=a.purchases_purchaser_id