SQL拆分日期范围

时间:2015-08-28 05:40:37

标签: sql sql-server tsql

我需要拆分日期范围,例如:

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

我使用此查询来拆分日期范围。但出于某种原因,我在下个月得到了额外的一行。这是错的。我该如何解决?

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 个答案:

答案 0 :(得分: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