Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Requête SQL pour combler les lacunes manquantes dans le temps et obtenir la dernière valeur non nulle

J'ai créé un SQL Fiddle de cette solution pour que vous puissiez jouer avec.

Essentiellement, il crée une table de travail @Months, puis Cross joint cette volonté toutes les années dans votre ensemble de données. Cela produit une liste complète de tous les mois pour toutes les années. J'ai ensuite laissé rejoindre les données de test fournies dans votre exemple (table nommée TEST - voir le violon SQL pour le schéma) dans cette liste pour me donner une liste complète avec des valeurs pour les mois qui les ont. Le problème suivant à surmonter consistait à utiliser les valeurs des derniers mois si ce mois-ci n'en avait pas. Pour cela, j'ai utilisé une sous-requête corrélée, c'est-à-dire jointe tblValues ​​sur elle-même uniquement là où elle correspondait au rang maximum d'une ligne qui a une valeur. Cela donne alors un jeu de résultats complet !

Si vous souhaitez filtrer par année\mois, vous pouvez l'ajouter dans une clause WHERE juste avant le dernier Order By.

Amusez-vous !

Schéma de test

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)

Requête

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