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

これは、私にとってまともな結果をもたらしていると思われる1つのアプローチです。

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

demo を使用した SQL Fiddle

より多くのデバッグ情報、つまり使用した x、x0、y などの値を含む別のSQL Fiddle 。

あなたのデータには週末がありませんが、行には週末も含まれると思いました。そうでない場合は、クエリを微調整できると確信しています。

于 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 に答える