Using a numbers table makes things easier. If you don't already have a numbers table you can use the following sql to create one (taken from this SO post):
SELECT TOP 10000 IDENTITY(int,0,1) AS Number
INTO Tally
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Tally ADD CONSTRAINT PK_Tally PRIMARY KEY CLUSTERED (Number)
To learn more about the numbers table and how to use it, read Jeff Moden's The "Numbers" or "Tally" Table: What it is and how it replaces a loop article.
Once you have a numbers table, it's fairly easy with versions 2012 or higher, using the EOMONTH
built in function:
DECLARE @Start date = '2015-01-01', @End date = '2017-01-01'
SELECT EOMONTH(DATEADD(MONTH, Number, @Start))
FROM Tally
WHERE Number < DATEDIFF(MONTH, @Start, @End)
For earlier versions, you can use DATEADD
with DATEDIFF
to get the last day of the previous month, and then simply add one month:
SELECT DATEADD(DAY, -DATEPART(DAY, @Start), (DATEADD(MONTH, Number+1, @Start)))
FROM Tally
WHERE Number < DATEDIFF(MONTH, @Start, @End)
See a live demo on rextester