在旋转时将值“向下”填充

时间:2015-10-22 18:12:04

标签: sql sql-server sql-server-2012

我正在做一个PIVOT命令。我的行标签是日期字段。我的列是[NY],[TX]等位置。源数据中的某些值为空,但是一旦它被转动,我想用日期顺序“填充”那些具有最后已知值的空值。

即如果列NY的值为1/1/2010但是为1/2/2010的值我想要填写从2010年1月1日到1/2/2010的值,以及任何其他的空日期下面直到另一个值已存在。所以基本上我用填充日期的相同数据填充空缺口,每个列都有数据。

我目前的透视查询示例是:

SELECT ReadingDate, [NY],[TX],[WI]
FROM 
    (SELECT NAME As 'NodeName', 
            CAST(FORMAT(readingdate, 'M/d/yyyy') as Date) As 'ReadingDate',
            SUM(myvalue) As 'Value' 
     FROM   MyTable) as SourceData 
PIVOT (SUM(Value) FOR NodeName IN ([NY],[TX],[WI])) as PivotTable 
Order BY ReadingDate

但我不知道怎么做这个“填充”来填补空值

示例源数据

1/1/2010, TX, 1
1/1/2010, NY, 5
1/2/2010, NY null
1/1/2010, WI, 3
1/3/2010, WI, 7
...

注意1/2和NY的1/3没有WI会导致枢轴结果中出现空值。还有一个空记录也导致null。对于NY,一旦转动1/2需要用5来填充,因为它是最后已知的值,但是1/3也需要一次转动5,因为该记录甚至不存在但是当转动时它会显示出来作为空值,因为它不存在,但另一个位置有记录。

1 个答案:

答案 0 :(得分:1)

这可能是SQL Server的痛苦。 ANSI支持LAG()上的一个很好的功能,称为IGNORE NULL,但SQL Server还没有支持它。我将从使用条件聚合(个人偏好)开始:

select cast(readingdate as date) as readingdate,,
       sum(case when name = 'NY' then value end) as NY,
       sum(case when name = 'TX' then value end) as TX,
       sum(case when name = 'WI' then value end) as WI
from mytable
group by cast(readingdate as date);

所以,我们必须更聪明一点。我们可以根据它们之前的非NULL值的数量将NULL值分配到组中。幸运的是,使用累积COUNT()函数很容易做到这一点。然后,我们可以使用MAX()(或MIN())获取此组中的一个非NULL值:

with t as (
      select cast(readingdate as date) as readingdate,
             sum(case when name = 'NY' then value end) as NY,
             sum(case when name = 'TX' then value end) as TX,
             sum(case when name = 'WI' then value end) as WI,
      from mytable
      group by cast(readingdate as date)
     ),
     t2 as (
      select t.*,
             count(NY) over (order by readingdate) as NYgrp,
             count(TX) over (order by readingdate) as TXgrp,
             count(WI) over (order by readingdate) as WIgrp
      from t
     )
select readingdate,
       coalesce(NY, max(NY) over (partition by NYgrp)) as NY,
       coalesce(TX, max(TX) over (partition by TXgrp)) as TX,
       coalesce(WI, max(WI) over (partition by WIgrp)) as WI
from t2;