如何在日期范围内为每个月创建新行?

问题描述

我需要创建一个视图,该视图为日期范围之间的每个月创建新行。 我的预订表的数据示例如下所示。

Booking ID  Booking Name   Start Date  End Date    Booked Days
1           HolidayUSA     1/01/2020   15/02/2020  46
2           HolidayEurope  20/01/2020  10/03/2020  50
3           HolidayUK      14/03/2020  19/03/2020  5

我想创建一个视图,该视图将在日期范围之间为每个月添加一个新记录,根据该月的天数计算预订天数,并添加月/年字段。

预期输出

Expected output table

我正在使用Microsoft sql Server。 任何帮助将不胜感激。

解决方法

这是我最接近的近似值:

declare @tb table  ([Booking Id] int,[Booking Name] varchar(30),[Start Date] datetime,[End Date] datetime)
-- Sample data
insert @tb values
    (1,'HolidayUSA','20200101','20200215'),(2,'HolidayEUROPE','20200120','20200310'),(3,'HolidayUK','20200314','20200319')

-- Showing sample data
select *,dateDiff(dd,[Start Date],[End Date]) [Booked Days]
from @tb

declare @dd smallint
select @dd = max(dateDiff(dd,[End Date])) from @tb

with day_cte as (
    select 1 as nbd union all
    select nbd + 1 from day_cte where nbd <= @dd)
select [Booking Id],[Booking Name],[End Date],datePart(yy,dateAdd(dd,nbd,[Start Date])) [Year],left(dateName(mm,[Start Date])),3) [Month],count(*) [Booked Days]
from @tb,day_cte
where nbd <= dateDiff(dd,[End Date])
group by [Booking Id],dateName(mm,[Start Date]))
,

这是一种基于计数或数字表的方法。计数CTE创建一个序列(最多12 ^ 4或20,736天(可以增加到必要的时间)),以将日历延长几天。然后按月汇总。

;with
n(n) as (select * from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) v(n)),tally_cte(N) as (
     select row_number() over (order by (select null)) 
     from n n1 cross join n n2 cross join n n3 cross join n n4)
select booking_id,booking_name,start_dt,end_dt,dfp.dfp,year(dt.booking_dt) [Year],convert(char(3),dt.booking_dt,0) [Month],count(*) booked_days
from #test t
     cross apply
     (select dateadd(d,n-1,t.start_dt) booking_dt 
      from tally_cte
      where n<=datediff(d,t.start_dt,t.end_dt)) dt
     cross apply
     (select datefromparts(year(dt.booking_dt),month(dt.booking_dt),1) dfp) dfp
group by booking_id,year(dt.booking_dt),0)
order by 1,3,5;

输出

booking_id          booking_name    start_dt    end_dt  dfp Year    Month   booked_days
1   HolidayUSA      2020-01-01      2020-02-15  2020-01-01  2020    Jan     31
1   HolidayUSA      2020-01-01      2020-02-15  2020-02-01  2020    Feb     14
2   HolidayEurope   2020-01-20      2020-03-10  2020-01-01  2020    Jan     12
2   HolidayEurope   2020-01-20      2020-03-10  2020-02-01  2020    Feb     29
2   HolidayEurope   2020-01-20      2020-03-10  2020-03-01  2020    Mar     9
3   HolidayUK       2020-03-14      2020-03-19  2020-03-01  2020    Mar     5