2013-11-28 9 views
5

Ho una tabella con due colonne chiamato "from_date" e "to_date"intervallo di date Spalato in una riga al mese in SQL Server

the table look like:- 

enter image description here

voglio risultare come: -

from_date   to_date 
-----------   ------------ 
2013-11-25   2013-11-30 
2013-12-01   2013-12-05 

Tale data è suddivisa tra 2013-11-25 e 2013-11-30 e un'altra data divisa dal 2013-12-01 al 2013-12-05 ... È possibile suddividere in questo modo?

+1

Quanto segue è * quasi * lo stesso. Funziona solo per mesi interi, ma dovrebbe essere banale modificarlo per funzionare anche su mesi parziali: http://stackoverflow.com/questions/7218526/split-date-range-into-months – Heinzi

+0

Se le date coprono 3 mesi per esempio '2013-11-25' a' 2014-02-05' dovrebbe essere suddiviso in 3 righe o 4? – GarethD

risposta

5

Questo è un anno bisestile e gestisce gli intervalli di date mentre le altre risposte attualmente non lo sono.

DECLARE @d TABLE(from_date DATE, to_date DATE); 

INSERT @d VALUES ('2013-11-25','2013-12-05'); 

;WITH n(n) AS 
(
    SELECT ROW_NUMBER() OVER (ORDER BY [object_id])-1 FROM sys.all_columns 
), 
d(n,f,t,md,bp,ep) AS 
(
    SELECT n.n, d.from_date, d.to_date, 
    DATEDIFF(MONTH, d.from_date, d.to_date), 
    DATEADD(MONTH, n.n, DATEADD(DAY, 1-DAY(from_date), from_date)), 
    DATEADD(DAY, -1, DATEADD(MONTH, 1, DATEADD(MONTH, n.n, 
     DATEADD(DAY, 1-DAY(from_date), from_date)))) 
FROM n INNER JOIN @d AS d 
ON d.to_date >= DATEADD(MONTH, n.n-1, d.from_date) 
) 
SELECT original_from_date = f, original_to_date = t, 
    new_from_date = CASE n WHEN 0 THEN f ELSE bp END, 
    new_to_date = CASE n WHEN md THEN t ELSE ep END 
FROM d WHERE md >= n 
ORDER BY original_from_date, new_from_date; 

Risultati:

original_from_date original_to_date new_from_date new_to_date 
------------------ ---------------- ------------- ----------- 
2013-11-25   2013-12-05   2013-11-25  2013-11-30 
2013-11-25   2013-12-05   2013-12-01  2013-12-05 

SQLFiddle demo with longer date ranges and leap years

+0

Questo ciò che voglio ... la tua query funziona bene @Aaron Bertrand. –

+0

Se il primo from_date è per un mese che segue un mese con meno di 31 giorni, la soluzione non riesce a trovare correttamente l'ultimo giorno del mese. Inizia con ottobre anziché novembre. Ottobre segue settembre e settembre ha meno di 31 giorni. – Kennah

+0

Non ho trovato questo. Martijn Vermunt ha fatto. http://stackoverflow.com/q/34514361/2471473 – Kennah

1

Se si opera in un data warehouse dimensionale, utilizzano la dimensione data. Altrimenti, usa CTE.

WITH cte AS 
(SELECT from_date 
     , to_date 
     , from_date AS mo_from_date 
     , DATEADD(day, day(from_date)* -1 + 1, from_date) AS bom_date 
    FROM DateTable 
UNION ALL 
SELECT from_date 
    , to_date 
    , DATEADD(month,1,bom_date) 
    , DATEADD(month,1,bom_date) 
    FROM cte 
where DATEADD(month,1,mo_from_date) < to_date 
) 
SELECT mo_from_date 
    , CASE when to_date < DATEADD(month,1,bom_date) THEN 
      to_date 
     ELSE 
      DATEADD(day, -1, DATEADD(month,1,bom_date)) 
     END AS mo_to_date 
    FROM cte 
Problemi correlati