Here are a couple of ways to achieve this. The first will only work on MySQL 8+ and uses a recursive CTE
to generate the months between StartDate
and EndDate
:
WITH RECURSIVE CTE AS (
SELECT ID, Startdate AS d, EndDate
FROM dates
UNION ALL
SELECT ID, d + INTERVAL 1 MONTH, EndDate
FROM CTE
WHERE d < EndDate
)
SELECT ID, DATE_FORMAT(d, '%M %Y') AS Dates
FROM CTE
ORDER BY ID, d
The second (which will run on any version of MySQL) uses a numbers table (in this case numbers from 0 to 99, allowing for a range of up to 99 months between StartDate
and EndDate
; if you need longer, adding more tables to the CROSS JOIN
will increase that range by a factor of 10 for each table added) to generate the list of months difference, this is then JOIN
ed to the original table so that the generated date Startdate + INTERVAL n.n MONTH
is less than or equal to EndDate
:
SELECT ID, DATE_FORMAT(Startdate + INTERVAL n.n MONTH, '%M %Y') AS Dates
FROM dates
JOIN (
SELECT n10.n * 10 + n1.n * 1 AS n
FROM (
SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n10
CROSS JOIN (
SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n1
) n ON Startdate + INTERVAL n.n MONTH <= EndDate
ORDER BY ID, Startdate + INTERVAL n.n MONTH
Having generated our list of dates, we format it using DATE_FORMAT
and a format string of %M %Y
. For both queries the output is:
ID Dates
1 January 2019
1 February 2019
1 March 2019
2 August 2019
2 September 2019
2 October 2019
2 November 2019
2 December 2019
2 January 2020
2 February 2020
Demo on dbfiddle