2013-02-25 3 views
2

У меня есть следующая функция, которая должна вернуть начальную и конечную даты месяцев между двумя месяцами, проблема в том, что с момента этого месяца 28 дней функция вычисляет все предстоящие месяцы на 28-дневной основе таким образом возвращая следующие неправильные значения.Получить начальную и конечную даты месяца между двумя датами в SQL?

StartDate EndDate 
----------------------- 
2013-02-01 2013-02-28 
2013-03-01 2013-03-28 
2013-04-01 2013-04-28 



declare @sDate datetime, 
     @eDate datetime; 

select @sDate = '2013-02-25', 
     @eDate = '2013-04-25'; 

;with months as 
(
    select DATEADD(mm,DATEDIFF(mm,0,@sDate),0) StartDate, 
    DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@sDate)+1,0)) EndDate 

    union all 
    select dateadd(mm, 1, StartDate), 
    dateadd(mm, 1, EndDate) 
    from months 
    where dateadd(mm, 1, StartDate)<= @eDate 
) 

select * from months 

Как я могу изменить это, чтобы возвращать правильные даты?

+0

Вы не должны использовать инклюзивный верхнего предела - вы должны сказать "меньше, чем в начале следующего месяца. Это неправильный способ думать о значениях даты/времени/времени, и [очевидно, что SQL Server имеет уникальный набор проблем] (http://sqlblog.com/blogs/aaron_bertrand/archive/2011/10/19/what-do -between-and-the-devil-have-in-common.aspx), чтобы справиться с этим. Итак, начните месяц, добавьте месяц и используйте инклюзивную нижнюю границу ('> =') и эксклюзивную верхнюю границу ('<'). –

ответ

6

Попробуйте это;

declare @sDate datetime, 
     @eDate datetime 

select @sDate = '2013-02-25', 
     @eDate = '2013-04-25' 

;with cte as (
    select convert(date,left(convert(varchar,@sdate,112),6) + '01') startDate, 
     month(@sdate) n 
    union all 
    select dateadd(month,n,convert(date,convert(varchar,year(@sdate)) + '0101')) startDate, 
     (n+1) n 
    from cte 
    where n < month(@sdate) + datediff(month,@sdate,@edate) 
) 
select startdate, dateadd(day,-1,dateadd(month,1,startdate)) enddate 
from cte 

FIDDLE DEMO

| STARTDATE | ENDDATE | 
--------------------------- 
| 2013-02-01 | 2013-02-28 | 
| 2013-03-01 | 2013-03-31 | 
| 2013-04-01 | 2013-04-30 | 
+0

Вы могли бы прокомментировать код и объяснить, что его делает, спасибо – Xerxes

+0

В side cte он получает начальные значения каждого месяца между датами и затем стороной cte. Я использую startdate, чтобы найти дату окончания того же месяца, используя dateadd функция. Это работает, даже если вы даете даты через два года. Играйте со скрипкой, которую вы поймете. – Kaf

1

Если вы хотите получить первый день месяца, используйте dateadd дважды, чтобы получить последний день.

Сначала добавьте 1 месяц, затем вычтите 1 день.

Смежные вопросы