查找最近的开始日期和月末

时间:2015-06-22 10:44:10

标签: sql sql-server tsql datetime

表包含特定参数的每日快照,但有些日子可能会丢失数据。任务是计算每月的金额,为此我们需要在月末开始/结束时的值,如果数据缺失,我们需要成对的最近日期,即:

[Time]                  Value
2015-04-28 00:00:00.000 76127
2015-05-03 00:00:00.000 76879
2015-05-22 00:00:00.000 79314
2015-06-07 00:00:00.000 81443

目前我使用以下代码:

select 
  * 
from(
  select 
    [Time],
    Value,
    ROW_NUMBER() over (partition by CASE WHEN [Time] < '2015-05-01' THEN 1 ELSE 0 END order by abs(DATEDIFF(DAY, '2015-05-01', [Time]))) as rn2,
    ROW_NUMBER() over (partition by CASE WHEN [Time] > '2015-05-01' THEN 1 ELSE 0 END order by abs(DATEDIFF(DAY, [Time], '2015-05-01'))) as rn3,
    ROW_NUMBER() over (partition by CASE WHEN [Time] < '2015-05-31' THEN 1 ELSE 0 END order by abs(DATEDIFF(DAY, '2015-05-31', [Time]))) as rn4,
    ROW_NUMBER() over (partition by CASE WHEN [Time] > '2015-05-31' THEN 1 ELSE 0 END order by abs(DATEDIFF(DAY, [Time], '2015-05-31'))) as rn5,
    DATEDIFF(DAY, '2015-05-01', [Time]) as doff,
    DATEDIFF(DAY, '2015-05-31', [Time]) as doff2
  from 
    ValueTable
  where 
    [Time] between '2015-04-01' and '2015-06-30'
) r
where
  doff = 0 or doff2 = 0 or (doff != 0 and rn2 = 1 and rn3 = 1) or (doff2 != 0 and rn4 = 1 and rn5 = 1)

有没有更有效的方法呢?

1 个答案:

答案 0 :(得分:0)

以下代码看起来会更复杂,因为它更长。但是,它应该非常快,因为它可以很好地利用ValueTable([Time])上的索引。

想法是寻找完全匹配。如果没有完全匹配,则查找日期之前和之后的第一个和最后一个记录。这需要在六个子查询上union all,但每个子查询都应该最佳地使用索引:

with exact_first as (
      select t.*
      from ValueTable t
      where [Time] = '2015-05-01'
     ),
     exact_last as (
      select t.*
      from ValueTable t
      where [Time] = '2015-05-01'
     )
(select ef.*
 from exact_first ef
) union all
(select top 1 t.*
 from ValueTable t
 where [Time] < '2015-05-01' and
       not exists (select 1 from exact_first ef2)
 order by [Time]
) union all
(select top 1 t.*
 from ValueTable t
 where [Time] > '2015-05-01' and
       not exists (select 1 from exact_first ef2)
 order by [Time] desc
) union all
(select el.*
 from exact_last el
) union all
(select top 1 t.*
 from ValueTable t
 where [Time] < '2015-05-31' and
       not exists (select 1 from exact_last ef2)
 order by [Time]
) union all
(select top 1 t.*
 from ValueTable t
 where [Time] > '2015-05-31' and
       not exists (select 1 from exact_last ef2)
 order by [Time] desc;
)