SQL Query用于填充跨时间的缺失空白并获取最后一个非空值

时间:2014-05-29 11:22:08

标签: sql-server sql-server-2012 gaps-and-islands

我的数据库中有以下表格:

Month|Year | Value
   1 |2013 | 100
   4 |2013 | 101
   8 |2013 | 102
   2 |2014 | 103
   4 |2014 | 104 

如何从数据中填写“缺失”行,以便在2013-03至2014-03期间查询时,我会得到:

Month|Year | Value
   3 |2013 | 100
   4 |2013 | 101
   5 |2013 | 101
   6 |2013 | 101
   7 |2013 | 101
   8 |2013 | 102
   9 |2013 | 102
  10 |2013 | 102
  11 |2013 | 102
  12 |2013 | 102
   1 |2014 | 102
   2 |2014 | 103
   3 |2014 | 103

正如您所看到的,我想重复之前的Value以查找缺失的行。

1 个答案:

答案 0 :(得分:5)

我已经为您创建了SQL Fiddle此解决方案。

基本上,它会创建一个工作表@Months,然后Cross会在数据集中连接这一年。这将生成所有年份所有月份的完整列表。然后,我将您的示例中提供的测试数据(名为TEST的表 - 请参阅模式的SQL小提琴)添加回此列表,以便为我提供包含具有它们的月份的值的完整列表。要解决的下一个问题是使用过去几个月的值,如果这几个月没有。为此,我使用了一个相关的子查询,即只有在匹配具有值的行的最大Rank时才将tblValues连接回自身。然后,这将给出一个完整的结果集!

如果您想按年/月过滤,可以在最终的Order By之前将其添加到WHERE子句中。

享受!

测试架构

CREATE TABLE TEST( Month tinyint, Year int, Value int)

INSERT INTO TEST(Month, Year, Value)
VALUES
   (1,2013,100),
   (4,2013,101),
   (8,2013,102),
   (2,2014,103),
   (4,2014,104)

<强>查询

DECLARE @Months Table(Month tinyint)
Insert into @Months(Month)Values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12);


With tblValues as (
  select Rank() Over (ORDER BY y.Year, m.Month) as [Rank], 
          m.Month, 
          y.Year, 
          t.Value
  from @Months m
  CROSS JOIN ( Select Distinct Year from Test ) y
  LEFT JOIN Test t on t.Month = m.Month and t.Year = y.Year
  )
Select t.Month, t.Year, COALESCE(t.Value, t1.Value) as Value
from tblValues t
left join tblValues t1 on t1.Rank = (
            Select Max(tmax.Rank)
            From tblValues tmax 
            Where tmax.Rank < t.Rank AND tmax.Value is not null)

Order by t.Year, t.Month