2016-12-17 6 views
1

Если вход предусмотрен, как показано нижеНайти начальную и конечную дату двух разных дат в SQL Server, группы по месяцам

declare @from datetime = '2016-09-15' 
declare @to datetime = '2016-12-25' 

Затем выход должен быть, как показано ниже

Month  Start_date End_date 
September 2016-09-15 2016-09-30 
October 2016-10-01 2016-10-31 
November 2016-11-01 2016-11-30 
December 2016-12-01 2016-12-25 

Если предусмотрен вход как это:

declare @from datetime = '2016-12-05' 
declare @to datetime = '2016-12-25' 

Тогда результат должен быть таким:

Month  Start_date End_date 
December 2016-12-05 2016-12-25 

Заранее спасибо.

+0

Просьба ** EXPLAIN ** на простом английском языке, что вы пытаетесь выполнить - не просто оставляйте нас ** угадыванием ** и недоумевая, что вы пытаетесь сделать! –

ответ

0

Это может быть достигнуто с помощью рекурсивного CTE

declare @from datetime = '2016-09-15' 
declare @to datetime = '2016-12-25' 

;with cte_r 
    AS 
    (
    SELECT 
      @from AS Dte1 
      ,@to AS Dte2 
      ,DATEADD(MM,DATEDIFF(MM,0,@from),0) AS MonthStrt 
      ,DATEADD(DD,-1,DATEADD(MM,DATEDIFF(MM,0,@from)+1,0)) AS MonthEnd 
    UNION ALL 
    SELECT 
      @from AS Dte1 
      ,@to AS Dte2 
      ,DATEADD(MM,1,MonthStrt) 
      ,DATEADD(MM,1,MonthEnd) 
    FROM 
      cte_r 
    WHERE 
     MonthEnd <= @to 
    ) 
SELECT   
    CASE WHEN MonthStrt <= @from THEN @from ELSE MonthStrt END AS Stat_Date 
    ,CASE WHEN MonthEnd >= @to THEN @to ELSE MonthEnd END AS End_Date 
FROM 
    cte_r 
1

Попробуйте это, я надеюсь, что это помогает.

DECLARE @fromDate DATE = '2016-09-05', @toDate DATE = '2016-12-25', @tempStartDate DATE 

    DECLARE @tempTable TABLE(Month NVARCHAR(50), Start_Date DATE, End_Date DATE) 

    SELECT @tempStartDate = @fromDate 

    WHILE(CAST(@tempStartDate AS DATE) <= CAST(@toDate AS DATE)) 
    BEGIN 

     INSERT INTO @tempTable 
      SELECT DATENAME(MONTH, @tempStartDate),@tempStartDate, 
      CASE WHEN DATEPART(MONTH,@tempStartDate) = DATEPART(MONTH,@toDate) THEN @toDate ELSE DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,@tempStartDate)+1,0)) END 
     SET @tempStartDate = DATEADD(s,1,DATEADD(mm, DATEDIFF(m,0,@tempStartDate)+1,0)) 

    END 

    SELECT * FROM @tempTable 
1

Вы можете сделать это с помощью специальной таблицы подсчета. Использование spt_values, но любая большая таблица будет делать.

Кроме того, этот подход будет быстрее, чем рекурсивный КТР, особенно для больших наборов

declare @from date = '2016-09-15' 
declare @to date = '2016-12-25' 

Select Month  = max(DateName(MONTH,D)) 
     ,Start_date = min(D) 
     ,End_date = max(D) 
From (Select Top (DateDiff(DD,@from,@to)+1) D=DateAdd(DD,Row_Number() Over (Order By (Select null))-1,@from) From master..spt_values) A 
Group By Year(D),Month(D) 
Order By min(d) 

Возвращает

Month  Start_date End_date 
September 2016-09-15 2016-09-30 
October  2016-10-01 2016-10-31 
November 2016-11-01 2016-11-30 
December 2016-12-01 2016-12-25 

Edit - Как Запрошенный

процесс действительно не что сложно. Мы используем Row_Number() совместно с DateAdd() для создания списка дат в пределах указанного диапазона дат.

Суб-запрос выдает следующие

D 
2016-09-15 
2016-09-16 
2016-09-17 
2016-09-18 
2016-09-19 
2016-09-20 
2016-09-21 
2016-09-22 
2016-09-23 
... 
2016-12-20 
2016-12-21 
2016-12-22 
2016-12-23 
2016-12-24 
2016-12-25 

Тогда становится простым вопросом получения/макс даты мин на год/месяц.

Опять же, я использовал master..spt_values, но практически любая таблица сделана. Если у вас нет таблицы с таблицами/цифрами, я бы настоятельно рекомендовал ее.

+0

Отличный результат. Не могли бы вы объяснить логику, которую вы использовали, так как это будет полезно. Еще раз, я ценю вас и большое спасибо. – Ram

+0

@Ram см. EDIT в обновленном ответе. –

+0

Мне нравится ваш метод, учитывая его +1. Я бы хотел разглядеть, что он делает, и посмотреть, могу ли я минимизировать стоимость сортировки. – pacreely

0
declare @from date = '2016-09-15' 

declare @to date = '2016-12-25'; 
with cte as 
(select datename(month,@from)as month1,1 as n , @from as startdate,eomonth(@from)as endate 
union all 
select datename(month,dateadd(day,n,@from)),n+1,dateadd(day,n,@from),eomonth(dateadd(day,n,@from)) 
from cte where dateadd(day,n,@from)<@to 
)select month1,min(startdate),max(endate) from cte 
group by month1 
order by 1 desc 
Смежные вопросы