这是一个使用datepart函数来说明您的周从星期一开始的事实的解决方案:
with demo_normalized as
(
select id,
start_date,
(datepart(dw,start_date) + 5) % 7 as test,
dateadd(d,
0 - ((datepart(dw,start_date) + 5) % 7),
start_date
) as start_date_firstofweek,
dateadd(d,
6 - ((datepart(dw,start_date) + 5) % 7),
start_date
) as start_date_lastofweek,
end_date,
dateadd(d,
0 - ((datepart(dw,end_date) + 5) % 7),
end_date
) as end_date_firstofweek,
dateadd(d,
6 - ((datepart(dw,end_date) + 5) % 7),
end_date
) as end_date_lastofweek,
datediff(week,
dateadd(d,
0 - ((datepart(dw,start_date) + 5) % 7),
start_date
),
dateadd(d,
6 - ((datepart(dw,end_date) + 5) % 7),
end_date
)
) as no_of_weeks
from demo
),
demo_cte as
(
select
id,
dateadd(day,7,start_date_firstofweek) as start_date,
dateadd(day,7,start_date_lastofweek) as end_date,
end_date_firstofweek,
no_of_weeks
from demo_normalized
where no_of_weeks >= 3
UNION ALL select
id,
dateadd(day,7,start_date) as start_date,
dateadd(day,7,end_date) as end_date,
end_date_firstofweek,
no_of_weeks
from demo_cte
where
(dateadd(day,8,start_date) < end_date_firstofweek)
),
demo_union as
(
select id, start_date, end_date, no_of_weeks from demo_normalized where no_of_weeks = 1
union all
select id, start_date, start_date_lastofweek as end_date, no_of_weeks
from demo_normalized where no_of_weeks >= 2
union all
select id, start_date, end_date, no_of_weeks from demo_cte
union all
select id, end_date_firstofweek as start_date, end_date, no_of_weeks
from demo_normalized where no_of_weeks >= 2
)
select
d0.id,
d0.no_of_weeks,
convert(varchar, d0.start_date, 106) as start_date,
convert(varchar, d0.end_date, 106) as end_date
from demo_union d0
order by d0.id, d0.start_date
编辑(在这之间的几周内添加了 CTE):这是sqlfiddle 的链接。
注意:此解决方案不需要额外的 DDL - 无需创建和维护额外的实体。简而言之,它不会重新发明日历。所有日历逻辑都包含在查询中。