Utworzyłem SQL Fiddle tego rozwiązania do zabawy.
Zasadniczo tworzy on tabelę roboczą @Months, a następnie Cross łączy ją z wszystkimi latami w zestawie danych. Daje to pełną listę wszystkich miesięcy ze wszystkich lat. Następnie zostawiłem dołączenie danych testowych podanych w twoim przykładzie (Tabela o nazwie TEST - zobacz skrzypce SQL dla schematu) z powrotem do tej listy, aby dać mi pełną listę z wartościami dla miesięcy, które je mają. Następnym problemem do przezwyciężenia było użycie wartości z ostatnich miesięcy, jeśli w tym miesiącu ich nie było. W tym celu użyłem skorelowanego podzapytania, tj. Połączyłem tblValues z powrotem tylko tam, gdzie pasowało do maksymalnej rangi wiersza, który ma wartość. To daje pełny zestaw wyników!
Jeśli chcesz filtrować według roku\miesiąca, możesz dodać to do klauzuli WHERE tuż przed ostatecznym zamówieniem według.
Ciesz się!
Schemat testowy
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)
Zapytanie
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