He creado un SQL Fiddle de esta solución para que juegues.
Esencialmente, crea una tabla de trabajo @Months y luego Cross se une a esto todos los años en su conjunto de datos. Esto produce una lista completa de todos los meses para todos los años. Luego dejé unir los datos de Prueba proporcionados en su ejemplo (Tabla llamada PRUEBA - vea el violín SQL para el esquema) de nuevo en esta lista para darme una lista completa con Valores para los meses que los tienen. El siguiente problema a superar fue usar los valores de los últimos meses si este mes no tenía ninguno. Para eso, utilicé una subconsulta correlacionada, es decir, uní tblValues solo donde coincidía con el Rango máximo de una fila que tiene un valor. ¡Esto da un conjunto de resultados completo!
Si desea filtrar por año/mes, puede agregarlo en una cláusula WHERE justo antes del pedido final por.
¡Disfrútalo!
Esquema de prueba
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)
Consulta
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