mercoledì 14 ottobre 2015

Calcolo numero mesi tra due date sql

Il seguente codice ritorna il numero di mesi tra due date sql.

DECLARE @dd1 date = '2015-01-01'
DECLARE @dd2 date = '2015-03-31'
SELECT DATEDIFF (month, @dd1, DATEADD(hour, 24, CAST(CAST(@dd2 AS DATE) AS DATETIME))) -
CASE
WHEN DATEPART(day, @dd1) > DATEPART(day, DATEADD(hour, 24, CAST(CAST(@dd2 AS DATE) AS DATETIME))) THEN 1 ELSE 0
END

Un mese viene ignorato se manca anche un solo giorno per completarlo, ad esempio facendo partire la data dal 2 gennaio perdiamo un mese
DECLARE @dd1 date = '2015-01-02'
DECLARE @dd2 date = '2015-03-31'

Questo mese può essere recuperato spostando la data finale di un giorno:
DECLARE @dd1 date = '2015-01-02'
DECLARE @dd2 date = '2015-04-01'

Continuità in una sequenza di date

Per verificare in sql se delle date DAL-AL in una tabella hanno date continue senza interruzioni si può utilizzare la seguente query:

-- Prepariamo la tabella per il test
DECLARE @table TABLE(PeriodoDal date, PeriodoAl date)
INSERT INTO @table VALUES ('2013-08-01', '2013-08-31')
INSERT INTO @table VALUES ('2013-09-01', '2013-09-30')
INSERT INTO @table VALUES ('2013-10-01', '2013-10-31')

-- Il valori ritornati dalle seguenti query devono coincidere
SELECT DATEDIFF(dd, MIN(PeriodoDal), MAX(PeriodoAl)) + 1 FROM @table
SELECT SUM(DATEDIFF(dd, PeriodoDal, PeriodoAl) + 1) FROM @table

-- Ritorna 0 se non ci sono interruzioni
SELECT DATEDIFF(dd, MIN(PeriodoDal), MAX(PeriodoAl)) - SUM(DATEDIFF(dd, PeriodoDal, PeriodoAl) + 1) + 1 FROM @table

Il codice verifica che la somma dei giorni nei singoli intervalli coincida con i giorni presenti nel range ricavabile con le istruzioni MIN() e MAX().

Per usare la query sql occorre assicurarsi che non ci siano sovrapposizioni tra date, ad esempio le seguenti righe sql dimostrano che un'interruzione nelle date viene compensata da una sovrapposizione:

-- sovrapposizione delle date
INSERT INTO @table VALUES ('2013-08-01', '2013-09-05')
INSERT INTO @table VALUES ('2013-09-01', '2013-09-30')
-- interruzione nelle date
INSERT INTO @table VALUES ('2013-10-06', '2013-10-31')