2013-03-25 117 views
1

我有两个表,我正在与。我们称他们为“客户”和“点数”。SQL滚动总计到某个日期

积分榜如下:

Account Year M01 M02 M03 M04 M05 M06 M07 M08 M09 M10 M11 M12 
123  2011 10 0 0 0 10 0 10 0 0 0 0 10 
123  2012 0 0 0 0 10 0 0 10 10 10 10 20 
123  2013 5 0 0 0 0 0 0 0 0 0 0 0 

但这些点上连续12个月的工作。计算当前客户的积分非常简单,但挑战在于不再活跃的客户。说客户123在2013年1月变得不活跃,我们只想计算2013年2月12日到2013年1月。这是其他表,客户,进来,让我们简化和说,它看起来就像这样:

Account End Date 
123  20130105 

现在,我想要做的就是创建一个计算出每个客户都有点的量查询。 (目前的12个月内活跃的客户,过去12个月中,他们活跃谁是不再有效客户。)

这里有一些更多的信息:

  • 我运行SQL Server 2008的
  • 这些表格已经提供给我这样,我不能修改它们。
  • 积极的客户是一个终止日期为99991231(Dec 31 9999)的人
  • 积分表仅填充客户是活跃客户的年数。也就是说,有人成为2009年2月份的活跃客户,如果他们2009年7月不活跃,他们的2009年2月至7月才会进入活跃状态,但2009年没有排名,因为他们不是客户那时候。 Jan & 2009年8月至12月将显示0。
  • 此外,只有客户在当年获得任何积分时才创建记录。如果客户一年获得0分,则不会有记录。
  • 对于边界案例,如果您进入一个月的第一天,那么将计算该月份。例如,假设今天是2013年4月1日,这意味着我们总结5月12日 - 4月13日。

这是一个相当复杂的问题。如果有什么我可以更好地解释,请让我知道。谢谢!

回答

4

不幸与points你的表结构,你将不得不unpivot的数据。一个unpivot将来自多个列的数据转换为行。一旦数据在行中,加入,过滤数据并为每个帐户累计点数将变得更加容易。到逆转置数据的代码将类似于此:

select account, 
    cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date, 
    pts 
from points 
unpivot 
(
    pts 
    for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12]) 
) unpiv 

SQL Fiddle with Demo。查询提供了一种类似于这样的结果:

| ACCOUNT | FULL_DATE | PTS | 
------------------------------ 
|  123 | 2011-01-01 | 10 | 
|  123 | 2011-02-01 | 0 | 
|  123 | 2011-03-01 | 0 | 
|  123 | 2011-04-01 | 0 | 
|  123 | 2011-05-01 | 10 | 

一旦数据是这种格式,你可以加入Customers表得到总的点,每个account,所以代码将类似于以下内容:

select 
    c.account, sum(pts) TotalPoints 
from customers c 
inner join 
(
    select account, 
     cast(cast(year as varchar(4))+'-'+replace(month_col, 'M', '')+'-01' as date) full_date, 
    pts 
    from points 
    unpivot 
    (
    pts 
    for month_col in ([M01], [M02], [M03], [M04], [M05], [M06], [M07], [M08], [M09], [M10], [M11], [M12]) 
) unpiv 
) p 
    on c.account = p.account 
where 
(
    c.enddate = '9999-12-31' 
    and full_date >= dateadd(year, -1, getdate()) 
    and full_date <= getdate() 
) 
or 
(
    c.enddate <> '9999-12-31' 
    and dateadd(year, -1, [enddate]) <= full_date 
    and full_date <= [enddate] 
) 
group by c.account 

SQL Fiddle with Demo

+0

非常感谢! – Julian 2013-03-26 12:41:39

2

糟糕的数据结构。要做的第一件事就是解开它。然后你得到一个以年 - 月分作为列的表格。

从这里,你可以选择最近12个月。事实上,你甚至不必担心客户什么时候离开,因为据推测他们从那时起就没有收集到积分。

下面是一个例子,SQL:

with points as (
    select 123 as account, 2012 as year, 
      10 as m01, 0 as m02, 0 as m03, 0 as m04, 10 as m05, 0 as m06, 
      10 as m07, 0 as m08, 0 as m09, 0 as m10, 0 as m11, 10 as m12 
    ), 
    points_ym as (
    select account, YEAR, mon, cast(right(mon, 2) as int) as monnum, points 
    from points 
    unpivot (points for mon in (m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, m12) 
    ) as unpvt 
    ) 
select account, SUM(points) 
from points_ym 
where year*12+monnum >= year(getdate())*12+MONTH(getdate()) - 12 
group by account 
+0

糟糕的数据结构,事实上,完全同意。感谢您的答复。 – Julian 2013-03-26 12:42:00