2013-11-28 6 views
5

Ich habe eine Tabelle mit zwei Spalte mit dem Namen "from_date" und "to_date"Split Datumsbereich in eine Zeile pro Monat in SQL Server

the table look like:- 

enter image description here

ich führen will wie: -

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

Dieses Datum wird vom 2013-11-25 bis 2013-11-30 und ein anderes Datum vom 2013-12-01 bis 2013-12-05 geteilt ... Ist es möglich, so zu teilen?

+1

Folgendes ist * fast * das gleiche. Es funktioniert nur für volle Monate, aber es sollte trivial sein, es zu ändern, um auch an Teilmonaten zu arbeiten: http://stackoverflow.com/questions/7218526/split-date-range-into-months – Heinzi

+0

Wenn die Daten 3 Monate umfassen z.B '2013-11-25 'bis' 2014-02-05 'sollte sich das in 3 Reihen oder 4 teilen? – GarethD

Antwort

5

Dies ist Schaltjahr sicher und behandelt Datumsbereiche die anderen Antworten derzeit nicht.

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; 

Ergebnisse:

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

Das was ich will ... Ihre Anfrage funktioniert gut @Aaron Bertrand. –

+0

Wenn das erste from_date für einen Monat ist, der auf einen Monat mit weniger als 31 Tagen folgt, findet Ihre Lösung den letzten Tag des Monats nicht richtig. Beginnen Sie mit Oktober statt November. Oktober folgt September, und September hat weniger als 31 Tage. – Kennah

+0

Ich habe das nicht gefunden. Martijn Vermunt hat es getan. http://StackOverflow.com/Q/34514361/2471473 – Kennah

1

Wenn Sie in einem dimensionalen Data Warehouse, nutzen die Datumsdimension arbeiten. Andernfalls verwenden Sie 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 
Verwandte Themen