2013-11-28 13 views
5

Mam tabeli z dwoma kolumnie o nazwie "FROM_DATE" i "to_date"Podział zakres dat w jednym rzędzie miesięcznie w serwerze sql

the table look like:- 

enter image description here

Chcę prowadzić jak: -

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

Ta data jest dzielona od 2013-11-25 do 2013-11-30, a kolejna data jest od 2013-12-01 do 2013-12-05 ... Czy można tak podzielić?

+1

Poniżej znajduje się * prawie * to samo. Działa tylko przez pełne miesiące, ale zmodyfikowanie go do pracy w niepełnych miesiącach powinno być trywialne: http://stackoverflow.com/questions/7218526/split-date-range-into-months – Heinzi

+0

Jeśli daty dotyczą 3 miesięcy na przykład '2013-11-25' to' 2014-02-05' powinno być podzielone na 3 wiersze lub 4? – GarethD

Odpowiedz

5

Ten rok przestępny jest bezpieczny i obejmuje zakresy dat, z których inne obecnie nie są dostępne.

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; 

Wyniki:

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

To, czego chcę ... twoje zapytanie działa dobrze @Aaron Bertrand. –

+0

Jeśli pierwsza data_zapasowa dotyczy miesiąca następującego po miesiącu, w którym jest mniej niż 31 dni, to rozwiązanie nie może poprawnie znaleźć ostatniego dnia miesiąca. Zacznij od października, a nie od listopada. Październik następuje po wrześniu, a wrzesień ma mniej niż 31 dni. – Kennah

+0

Nie znalazłem tego. Martijn Vermunt to zrobił. http://stackoverflow.com/q/34514361/2471473 – Kennah

1

Jeśli działają w wymiarowego hurtowni danych, wykorzystują wymiar daty. W przeciwnym razie użyj 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 
Powiązane problemy