将多月记录拆分为单独的月份

Split multi-month records into individual months

我在 table 中有这种格式的数据 - 其中日期范围是多月:

SourceSink  Class   ShadowPrice Round   Period  StartDate   EndDate
 AEC        Peak    447.038      3     WIN2020  2020-12-01  2021-02-28

我想创建一个视图/插入一个新的 table - 以上记录按月打破,如下所示:

SourceSink  Class   ShadowPrice Round   Period  StartDate   EndDate
 AEC        Peak    447.038      3     WIN2020  2020-12-01  2021-12-31
 AEC        Peak    447.038      3     WIN2020  2021-01-01  2021-01-31
 AEC        Peak    447.038      3     WIN2020  2021-02-01  2021-02-28

请指教

一个选项是递归查询。假设经期总是从一个月的第一天开始到一个月的最后一天结束,如示例数据所示,则为:

with cte as (
    select t.*, startDate newStartDate, eomonth(startDate) newEndDate
    from mytable t
    union all
    select 
        sourceSink,
        class,
        shadowPrice,
        period,
        startDate,
        endDate,
        dateadd(month, 1, newStartDate),
        eomonth(dateadd(month, 1, newStartDate))
    from cte
    where newStartDate < endDate
)
select * from cte

如果月经开始和结束的日期不同,那么我们需要多一点逻辑:

with cte as (
    select 
        t.*, 
        startDate newStartDate, 
        case when eomonth(startDate) <= endDate then eomonth(startDate) else endDate end newEndDate
    from mytable t
    union all
    select 
        sourceSink,
        class,
        shadowPrice,
        period,
        startDate,
        endDate,
        dateadd(month, 1, datefromparts(year(newStartDate), month(newStartDate), 1)),
        case when eomonth(dateadd(month, 1, datefromparts(year(newStartDate), month(newStartDate), 1))) <= endDate
            then eomonth(dateadd(month, 1, datefromparts(year(newStartDate), month(newStartDate), 1)))
            else endDate
        end
    from cte
    where datefromparts(year(newStartDate), month(newStartDate), 1) < endDate
)
select * from cte

只是使用 CROSS APPLY 和临时计数 table

的另一种选择

例子

Select A.[SourceSink]
      ,A.[Class]
      ,A.[ShadowPrice]
      ,A.[Round]
      ,A.[Period]
      ,B.[StartDate]
      ,B.[EndDate]
 From YourTable A
 Cross Apply (
                Select StartDate=min(D)
                      ,EndDate  =max(D)
                  From (
                         Select Top (DateDiff(DAY,[StartDate],[EndDate])+1) 
                                D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),[StartDate]) 
                          From  master..spt_values n1,master..spt_values n2
                       ) B1
                  Group By Year(D),Month(D)
             ) B

Returns