4

我在下面有一组数据,其中包含 MS SQL 2005 中的日期和值。某些日期的值为 NULL。用线性插值填充 Null 值的最佳方法是什么?

Date,ShortName,LongName,Value
12/31/2012,ABC,Test1,-4.0
12/31/2012,XYZ,Test2,-8.1
1/2/2013,ABC,Test1,NULL
1/2/2013,XYZ,Test2,NULL
1/3/2013,ABC,Test1,NULL
1/3/2013,XYZ,Test2,NULL
1/4/2013,ABC,Test1,-9.6
1/4/2013,XYZ,Test2,-13.0
1/7/2013,ABC,Test1,NULL
1/7/2013,XYZ,Test2,NULL
1/8/2013,ABC,Test1,NULL
1/8/2013,XYZ,Test2,NULL
1/9/2013,ABC,Test1,NULL
1/9/2013,XYZ,Test2,NULL
1/10/2013,ABC,Test1,NULL
1/10/2013,XYZ,Test2,NULL
1/11/2013,ABC,Test1,-7.1
1/11/2013,XYZ,Test2,-12.7
4

2 回答 2

2

这是一种似乎给我带来不错结果的方法:

select *
from tests
where value is not null
union all
select t.Date
  , t.ShortName
  , t.LongName
  , Value = p.Value + (n.Value - p.Value)
    * (cast(datediff(dd, p.Date, t.Date) as decimal(16,1)))
    / (cast(datediff(dd, p.Date, n.Date) as decimal(16,1)))
from tests t
  cross apply
  (
    select top 1 p.date, p.value
    from tests p
    where p.Value is not null
      and t.shortname = p.shortname
      and t.date > p.date
    order by p.date desc
  ) p
  cross apply
  (
    select top 1 n.date, n.value
    from tests n
    where n.Value is not null
      and t.shortname = n.shortname
      and t.date < n.date
    order by n.date
  ) n
where t.Value is null
order by ShortName, Date

SQL Fiddle 与演示

另一个带有更多调试信息的SQL Fiddle,即我使用的 x、x0、y 等值。

尽管您的数据没有周末,但我认为该行也将包括周末。如果不是,我确定可以调整查询。

于 2013-05-24T21:58:34.927 回答
1

不清楚您是否只想在每个 ShortName 内或整个日期范围内进行插值。这是更简单的日期范围,但如果您也想按 ShortName 进行分区,请回复。

declare @Table table ([Date] datetime, ShortName varchar(100), LongName varchar(100), Value decimal(10,2));
insert into @Table
    select '12/31/2012','ABC','Test1','-4.0' union all
    select '12/31/2012','XYZ','Test2','-8.1' union all
    select '1/2/2013','ABC','Test1',NULL union all
    select '1/2/2013','XYZ','Test2',NULL union all
    select '1/3/2013','ABC','Test1',NULL union all
    select '1/3/2013','XYZ','Test2',NULL union all
    select '1/4/2013','ABC','Test1','-9.6' union all
    select '1/4/2013','XYZ','Test2','-13.0' union all
    select '1/7/2013','ABC','Test1',NULL union all
    select '1/7/2013','XYZ','Test2',NULL union all
    select '1/8/2013','ABC','Test1',NULL union all
    select '1/8/2013','XYZ','Test2',NULL union all
    select '1/9/2013','ABC','Test1',NULL union all
    select '1/9/2013','XYZ','Test2',NULL union all
    select '1/10/2013','ABC','Test1',NULL union all
    select '1/10/2013','XYZ','Test2',NULL union all
    select '1/11/2013','ABC','Test1','-7.1' union all
    select '1/11/2013','XYZ','Test2','-12.7'


;with stage as
(
    select  *, [r] = row_number() over (order by [Date])
    from    @Table
)
select  l.[Date], 
        [OldValue] = l.value,
        [NewValue] = isnull(l.Value, f.Value + (t.Value - f.Value) * (l.[r] - f.[r]) / (t.[r] - f.[r]))
from    stage l
outer 
apply   (   select  top 1 [Date], Value, [r]
            from    stage x
            where   x.[Date] < l.[Date] and
                    x.Value is not null
            order 
            by      [Date] desc
        ) f
outer 
apply   (   select  top 1 [Date], Value, [r]
            from    stage x
            where   x.[Date] > l.[Date] and
                    x.Value is not null
            order 
            by      [Date] asc
        ) t
order
by      [date] asc;
于 2013-05-24T22:06:14.597 回答