Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL-Abfrage, um fehlende Lücken im Laufe der Zeit zu füllen und den letzten Nicht-Null-Wert zu erhalten

Ich habe eine SQL Fiddle erstellt dieser Lösung zum Spielen.

Im Wesentlichen erstellt es eine Arbeitstabelle @Months und verbindet diese dann alle Jahre in Ihrem Datensatz. Dies erzeugt eine vollständige Liste aller Monate für alle Jahre. Ich habe dann die in Ihrem Beispiel bereitgestellten Testdaten (Tabelle mit dem Namen TEST - siehe SQL-Fiddle für Schema) wieder in diese Liste eingefügt, um mir eine vollständige Liste mit Werten für die Monate zu geben, in denen sie vorhanden sind. Das nächste zu überwindende Problem war die Verwendung der Werte des letzten Monats, wenn dieser Monat keine hatte. Dafür habe ich eine korrelierte Unterabfrage verwendet, dh tblValues ​​nur dann mit sich selbst verbunden, wenn sie mit dem maximalen Rang einer Zeile übereinstimmt, die einen Wert hat. Dies ergibt dann eine vollständige Ergebnismenge!

Wenn Sie nach Jahr\Monat filtern möchten, können Sie dies in eine WHERE-Klausel direkt vor dem letzten Order By einfügen.

Viel Spaß!

Testschema

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)

Abfrage

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