2015-08-28 6 views
1

мне нужно разделить диапазон дат, например:SQL Сплит диапазон дат

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 

Я использую этот запрос для разделения DateRange. Но по какой-то причине я получаю дополнительную строку со следующим месяцем. что неправильно. Как я могу это исправить?

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(MONTH, n.n+1, DATEADD(DAY, 0-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; 

Но по какой-то причине,

+1

Я побежал запрос и получил два ряда с новая дата с 25 ноября по 30 ноября и 1 дека до 5 децитов - это то, что вы хотите. Я не понимаю, в чем проблема. –

+0

Попробуйте добавить результат запроса и выделите проблему, с которой вы сталкиваетесь. –

+1

Несвязанный, но: вам не нужно ';' перед 'with', если вы уже правильно завершили предыдущий оператор с помощью'; ' –

ответ

0

Вы также можете попробовать использовать рекурсивный способ сделать это:

WITH CTE as 
    (
    SELECT from_date,To_date,from_date as BEG_D, 
      CASE WHEN DATEADD(DAY,-DAY(DATEADD(MONTH,1, d.from_date)), 
            DATEADD(MONTH,1, d.from_date)) 
         < To_date 
         THEN DATEADD(DAY,-DAY(DATEADD(MONTH,1, d.from_date)), 
             DATEADD(MONTH,1, d.from_date)) 
         ELSE To_Date END as END_D 
     FROM D 
     UNION ALL 
     SELECT from_date,To_date,DATEADD(DAY,1,END_D) as BEG_D, 
      CASE WHEN DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1,END_D))) 
         < To_date 
         THEN DATEADD(DAY,-1,DATEADD(MONTH,1,DATEADD(DAY,1,END_D))) 
         ELSE To_Date END as END_D 
     FROM CTE WHERE END_D < To_Dat 
    ) 
     SELECT * FROM CTE ORDER BY from_date,END_D; 

SQLFiddle demo

Смежные вопросы