SQL滚动总计达到某个日期

时间:2013-03-25 18:50:40

标签: sql sql-server-2008

我正在使用两张桌子。我们称之为“客户”和“积分”。

点数表如下所示:

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年1月12日至1月1日。这是另一个表,Customers,其中的内容,让我们简化并说它看起来像这样:

Account   End Date
123       20130105

现在,我想要做的是创建一个计算每个客户拥有的点数的查询。 (活跃客户目前为12个月,过去12个月他们对不再活跃的客户有效。)

以下是更多信息:

  • 我正在运行SQL Server 2008.
  • 这些表格已经提供给我,我无法修改它们。
  • 活跃客户的结束日期为99991231(1999年12月31日)
  • 积分表仅填充客户是活跃客户的年份。 Aka,有人成为活跃客户2009年2月,他们有2009年入职,如果他们在2009年7月变得不活跃,他们的积分只计算2009年2月至7月,因为他们不是客户,所以2008年没有排那时候。简& 2009年8月至12月将显示0。
  • 此外,仅当客户获得当年的任何积分时才会创建记录。如果客户一年获得0分,则不会有记录。
  • 对于边境案件,如果您进入一个月的第一天,则计算该月份。例如,今天是2013年4月1日,这意味着我们总结了5月12日至4月13日。

这是一个非常复杂的问题。如果有什么我可以解释得更好,请告诉我。谢谢!

2 个答案:

答案 0 :(得分:4)

不幸的是,对于points的表结构,您必须取消数据。 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

答案 1 :(得分: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