在SQL Server中按月查找两个不同日期的开始和结束日期

时间:2016-12-17 10:37:29

标签: sql sql-server sql-server-2008

如果提供如下输入

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

提前致谢。

4 个答案:

答案 0 :(得分: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 :(得分:1)

您可以使用临时计数表执行此操作。使用spt_values,但任何更大的表都可以。

此外,这种方法比递归cte更快,特别是对于更大的集合

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
  

修改 - 按要求

这个过程真的不那么复杂。我们与DateAdd()一起使用Row_Number()来生成指定日期范围内的日期列表。

子查询产生以下

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,但实际上任何表都可以。如果你没有理货/数字表,我强烈推荐一个。

答案 2 :(得分: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

答案 3 :(得分: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