将日期范围分成多行

时间:2018-10-19 18:30:09

标签: sql sql-server-2014

比方说,我有一个下表,如下所示(具有多个日期范围的多个项目):

Project | Start_Date | End_Date
ABC123    10/19/2018     12/31/2018

是否可以将其查询到如下所示的结果集中?

Project | Start_Date | End_Date
ABC123    10/19/18     10/31/18
ABC123    11/01/18     11/30/18
ABC123    12/01/18     12/31/18

2 个答案:

答案 0 :(得分:1)

这可能需要更多的优化,但要像现在一样提供预期的输出

 WITH TEMP1 (PROJECT,START_DATE , END_DATE, DT) AS                   
(                                                      
  SELECT PROJECT,START_DATE 
        ,END_DATE
        ,START_DATE DT              
    FROM MYTABLE
   UNION ALL                                          
  SELECT PROJECT
        ,START_DATE 
        ,END_DATE
        ,DATEADD(DAY, 1, DT) DT            
    FROM TEMP1                                           
   WHERE DT < END_DATE                                    
)                  
,TEMP2 AS(
  SELECT PROJECT
        ,DATEADD(MONTH, DATEDIFF(MONTH, 0, DT), 0) STARTDATE 
        ,EOMONTH(DT ) ENDDATE                                            
    FROM TEMP1
   GROUP BY PROJECT
           ,DATEADD(MONTH, DATEDIFF(MONTH, 0, DT), 0)  
           ,EOMONTH(DT ) 
)

SELECT B.PROJECT
      ,CASE WHEN B.STARTDATE < A.START_DATE THEN A.START_DATE 
            ELSE B.STARTDATE END AS STARTDATEFINAL
      ,CASE WHEN B.ENDDATE > A.END_DATE THEN A.END_DATE 
            ELSE B.ENDDATE END AS ENDDATEFINAL
  FROM MYTABLE A, TEMP2 B
 WHERE A.PROJECT = B.PROJECT

答案 1 :(得分:0)

您可以使用递归CTE:

with cte as (
      select project, start_date, eomonth(start_date) as end_date, end_date as final_date
      from t
      union all
      select project, dateadd(day, 1, end_date), eomonth(dateadd(day, 1, end_date)), final_date
      from cte
      where end_date < final_date
     )
select project_start_date, end_date
from cte;

请注意,您的问题在某些方面有点模棱两可。值得注意的是,这假定:

  • 结束日期与开始日期不在同一个月。
  • 结束日期总是在月底(或等效地,您总是希望最后一条记录在月底)。

这些与您的样本数据一致。使用条件逻辑修改查询以处理这些问题非常容易。

编辑:

对于注释中的条件:

with cte as (
      select project, start_date,
             (case when end_date < eomonth(start_date) then end_date
                   else eomonth(start_date)
              end) as end_date,
             end_date an final_date
      from t
      union all
      select project, start_date,
             (case when end_date < eomonth(start_date) then end_date
                   else eomonth(start_date)
              end) as end_date,
             end_date as final_date
      from t
      union all
      select project, dateadd(day, 1, end_date),
             (case when final_date < eomonth(dateadd(day, 1, end_date))
                   then final_date
                   else eomonth(dateadd(day, 1, end_date))
              end), final_date
      from cte
      where end_date < final_date
     )
select project_start_date, end_date
from cte;

这里是db<>fiddle