这是我启发的问题:How to get all the monthly intervals between two dates?
QA在那里向Oracle提出问题,我喜欢这个问题,并希望在SQL Server 2008中这样做。
让我重新解释一下这个问题。假设我们有以下数据:
Event StartDate EndDate
A 2018-02-07 2018-04-22
然后预期的输出将是:
Event Date
A 7 to 28
A 1 to 31
A 1 to 22
基本上,输出应显示EndDate和StartDate之间的日间隔。我用下面的查询处理了这个问题,效果很好,但我想知道是否有更好的方法来处理这个问题。任何建议将不胜感激!。
create table #temptable
([Event] varchar(5), dateinterval varchar(30))
declare @startDate date = '2018-02-07'
declare @endDate date = '2018-04-22'
declare @yeardiff int = (select DATEDIFF(month,@startDate,@endDate))
declare @counter int = 0
declare @tempDate date, @lastDateOfMonth date
declare @dateInterval varchar(100)
while @counter <= @yeardiff
begin
set @tempDate = @startDate
set @lastDateOfMonth = DATEADD(month, ((YEAR(@startDate) - 1900) * 12) + MONTH(@startDate), -1)
if @counter = @yeardiff
begin
set @dateInterval = cast(DAY(@startDate) as varchar(2)) + ' to ' + cast(DAY(@endDate) as varchar(2))
end
else
begin
set @dateInterval = cast(DAY(@startDate) as varchar(2)) + ' to ' + cast(DAY(@lastDateOfMonth) as varchar(2))
end
insert into #temptable
values ('B',@dateInterval)
set @startDate = DATEADD(m, DATEDIFF(m, -1, @startDate), 0)
set @counter = @counter + 1
end
select * from #temptable
答案 0 :(得分:3)
这在SQL Server中更容易,因为您可以使用递归CTE。 (实际上,在Oracle 12C中也有这些,所以同样的方法也可以。)
with CTE as (
select event, startdate, enddate,
dateadd(day, 1 - day(startdate), startdate) as month_start
from t
union all
select event, startdate, enddate,
dateadd(month, 1, month_start)
from cte
while month_start <= enddate
)
select event, month_start,
((case when eomonth(enddate) = eomonth(month_start) -- last month
then day(enddate)
else day(eomonth(month_start))
end) -
(case when month_start < startdate -- first month
then day(startdate) - 1
else 0
end)
) as days_in_month
from cte;
这会逐个扩展每个事件的日期范围。然后计算当月的天数。
默认情况下,这最长可达100个月。如果您需要支持更长时间,可以使用maxrecursion
选项。