Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Query SQL per colmare le lacune mancanti nel tempo e ottenere l'ultimo valore non nullo

Ho creato un SQL Fiddle di questa soluzione con cui giocare.

In sostanza, crea una tabella di lavoro al mese e quindi Cross si unisce a questo per tutti gli anni nel tuo set di dati. Questo produce un elenco completo di tutti i mesi per tutti gli anni. Ho quindi lasciato unire i dati di test forniti nel tuo esempio (Tabella denominata TEST - vedi SQL fiddle per lo schema) in questo elenco per darmi un elenco completo con i valori per i mesi che li hanno. Il problema successivo da superare è stato l'utilizzo dei valori degli ultimi mesi se questi mesi non ne avevano. Per questo, ho usato una sottoquery correlata, ad es. tblValues ​​unito su se stesso solo dove corrispondeva al Rank massimo di una riga che ha un valore. Questo dà quindi un set di risultati completo!

Se desideri filtrare per anno\mese puoi aggiungerlo in una clausola WHERE appena prima dell'ordine finale entro.

Divertiti!

Schema di prova

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)

Interroga

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