将计算列添加到数据透视表

时间:2014-02-04 02:01:37

标签: sql sql-server pivot

我有一张如下表格

Item Name | Date       | Previous Data | Updated Data
Unit 1    | 1-Jul-2013 | 500           | 550 
Unit 1    | 1-Aug-2013 | 550           | 550
Unit 1    | 1-Sep-2013 | 450           | 600 
Unit 1    | 1-Oct-2013 | 600           | 550

使用pivot功能,我将它们显示如下:

Title     | Jul | Aug   | Sep | Oct
Prev. Data| 500 | 550   | 450 | 600
Upd. Data | 550 | 550   | 600 | 550

现在,这是我想要实现的棘手部分。上一篇数据预先作为预测方式键入。当实际月份到来时,我们才会键入Upd。数据。

我想在上个月(即12月)旁边添加另一个名为YTD的列(年初至今),该列计算每个类别的加权平均值。假设我们现在在十月,加权平均计算方法将是

YTD = (Jan*(#Days in Jan) + Feb*(#Days in Feb) + ... + Oct*(#Days in Oct))/(Total days in a year)

目前,我的查询如下所示;

Select col,
[1] as Jan,
[2] Feb,
[3] Mar,
[4] Apr,
[5] May,
[6] Jun,
[7] Jul,
[8] Aug,
[9] Sep,
[10] Oct,
[11] Nov,
[12] Dec, 
(isnull([1],0)+isnull([2],0)+isnull([3],0))/3 as Q1, 
(isnull([4],0)+isnull([5],0)+isnull([6],0))/3 as Q2, 
(isnull([7],0)+isnull([8],0)+isnull([9],0))/3 as Q3, 
(isnull([10],0)+isnull([11],0)+isnull([12],0))/3 as Q4
from 
(
  select month(Date) as TMonth, col, value
  from Table1
  cross apply
  (
    select 'Previous Data', [Previous Data]
    union all
    select 'Updated Date', [Updated Data]
  ) c(col, value)
)a
PIVOT
(
 AVG(value)
 for Tmonth in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
)pvt

请有人帮助我如何实现这一目标吗?

我正在使用SQL Server 2008 R2

1 个答案:

答案 0 :(得分:0)

这有点棘手,但这里是包含YTD_WtdAvg列的更新查询。我在结果中添加了年份,因为为了根据一个月和一年中的天数进行wtd avg,您必须知道自2月以来的数据年份是否有不同的天数取决于年份

根据YTD = (Jan*(#Days in Jan) + Feb*(#Days in Feb) + ... + Oct*(#Days in Oct))/(Total days in a year)的OP公式,查询仍然会除以一年中的总天数,即使今天不是十二月。

Select
pvt.TYear, 
pvt.FirstDayOfYear,
pvt.DaysInYear,
pvt.col,
[1] as Jan,
[2] Feb,
[3] Mar,
[4] Apr,
[5] May,
[6] Jun,
[7] Jul,
[8] Aug,
[9] Sep,
[10] Oct,
[11] Nov,
[12] Dec, 
(isnull([1],0)+isnull([2],0)+isnull([3],0))/3 as Q1, 
(isnull([4],0)+isnull([5],0)+isnull([6],0))/3 as Q2, 
(isnull([7],0)+isnull([8],0)+isnull([9],0))/3 as Q3, 
(isnull([10],0)+isnull([11],0)+isnull([12],0))/3 as Q4,
(
      case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 1 then isnull(pvt.[1] * datediff(day, dateadd(month, 0, pvt.FirstDayOfYear), dateadd(month, 1, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 2 then isnull(pvt.[2] * datediff(day, dateadd(month, 1, pvt.FirstDayOfYear), dateadd(month, 2, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 3 then isnull(pvt.[3] * datediff(day, dateadd(month, 2, pvt.FirstDayOfYear), dateadd(month, 3, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 4 then isnull(pvt.[4] * datediff(day, dateadd(month, 3, pvt.FirstDayOfYear), dateadd(month, 4, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 5 then isnull(pvt.[5] * datediff(day, dateadd(month, 4, pvt.FirstDayOfYear), dateadd(month, 5, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 6 then isnull(pvt.[6] * datediff(day, dateadd(month, 5, pvt.FirstDayOfYear), dateadd(month, 6, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 7 then isnull(pvt.[7] * datediff(day, dateadd(month, 6, pvt.FirstDayOfYear), dateadd(month, 7, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 8 then isnull(pvt.[8] * datediff(day, dateadd(month, 7, pvt.FirstDayOfYear), dateadd(month, 8, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 9 then isnull(pvt.[9] * datediff(day, dateadd(month, 8, pvt.FirstDayOfYear), dateadd(month, 9, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 10 then isnull(pvt.[10] * datediff(day, dateadd(month, 9, pvt.FirstDayOfYear), dateadd(month, 10, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 11 then isnull(pvt.[11] * datediff(day, dateadd(month, 10, pvt.FirstDayOfYear), dateadd(month, 11, pvt.FirstDayOfYear)), 0) else 0 end 
    + case when pvt.TYear < year(getdate()) OR pvt.TYear = year(getdate()) AND month(getdate()) <= 12 then isnull(pvt.[12] * datediff(day, dateadd(month, 11, pvt.FirstDayOfYear), dateadd(month, 12, pvt.FirstDayOfYear)), 0) else 0 end 

)
 / pvt.DaysInYear
 as YTD_WtdAvg
from 
(
  select year(Date) as TYear
    , d.FirstDayOfYear
    , datediff(day, d.FirstDayOfYear, dateadd(year, 1, d.FirstDayOfYear)) as DaysInYear
    , month(date) as TMonth
    , col, value
  from Table1 t
  cross apply
  (
    select 'Previous Data', [Previous Data]
    union all
    select 'Updated Data', [Updated Data]
  ) c(col, value)
  cross apply 
  (
    select dateadd(year, datediff(year, 0, t.date), 0) as FirstDayOfYear
  ) d
)a
PIVOT
(
 AVG(value)
 for Tmonth in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
)pvt