I have the following table in my database:
Month|Year | Value
1 |2013 | 100
4 |2013 | 101
8 |2013 | 102
2 |2014 | 103
4 |2014 | 104
How can I fill in "missing" rows from the data, so that if I query from 2013-03 through 2014-03, I would get:
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
As you can see I want to repeat the previous Value
for a missing row.
I have created a SQL Fiddle of this solution for you to play with.
Essentially it creates a Work Table @Months and then Cross joins this will all years in your data set. This produces a complete list of all months for all years. I then left join the Test data provided in your example (Table named TEST - see SQL fiddle for schema) back into this list to give me a complete list with Values for the months that have them. The next issue to overcome was using the last months values if this months didn't have any. For that, I used a correlated sub-query i.e. joined tblValues back on itself only where it matched the maximum Rank of a row which has a value. This then gives a complete result set!
If you want to filter by year\month you can add this into a WHERE clause just before the final Order By.
Enjoy!
Test Schema
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)
Query
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