我需要一个给定日期范围SQL Server的动态月份列表(包括第一天和最后一天)

时间:2016-06-10 01:47:58

标签: sql-server date

如果@EndDate在2015年内设置为任何内容,则下面的代码可以使用,但是当它是@StartDate日历年之后的日期时,它将在2015年3月12日停止。有人可以帮助我,我希望能够使用它来在用户定义的日期范围之间使用所有月份。

DECLARE @StartDate DATE
DECLARE @EndDate DATE


set @StartDate = '1/1/2015' 
set @EndDate =  '12/31/2016'



SELECT 
    cast(dateadd(m, month-1, @StartDate) as date) begin_month,
    cast(dateadd(m, month, dateadd(year, datediff(year, 0, @StartDate), -1)) as date) end_month
FROM (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)) x(month)
WHERE 
    cast(dateadd(m, month-1, @StartDate) as date) >= @StartDate
and
    cast(dateadd(m, month, dateadd(year, datediff(year, 0, @EndDate), -1)) as date) <= @EndDate

1 个答案:

答案 0 :(得分:2)

你几乎就在那里。不要只使用12行,而是尝试使用更多行。在这里,我创建了一个最多10,000行的Tally Table。然后,使用TOP来限制行数,具体取决于DATEDIFF(MONTH, @StartDate, @EndDate) + 1。有了它,您不再需要添加WHERE子句:

DECLARE @StartDate  DATE,
        @EndDate    DATE

SELECT  @StartDate  = '20150101',
        @EndDate    = '20161231'

;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
    SELECT TOP(DATEDIFF(MONTH, @startDate, @endDate) + 1)
        ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
    FROM E4
)
SELECT 
    begin_month = DATEADD(MONTH, N-1, @startDate),
    end_month   = DATEADD(DAY, -1, DATEADD(MONTH, N, @startDate))
FROM CteTally

ONLINE DEMO