Вот несколько способов добиться этого. Первый будет работать только на MySQL 8+ и использует рекурсивный CTE
для генерации месяцев между StartDate
и 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
Второй (который будет работать на любой версии MySQL) использует таблицу чисел (в данном случае числа от 0 до 99, что позволяет в диапазоне до 99 месяцев между StartDate
и EndDate
; если вам нужно больше, добавление дополнительных таблиц к CROSS JOIN
будет увеличьте этот диапазон в 10 раз для каждой добавленной таблицы), чтобы сгенерировать разницу в списке месяцев, после чего она JOIN
будет преобразована в исходную таблицу, чтобы сгенерированная дата Startdate + INTERVAL n.n MONTH
была меньше или равна 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
Сформировав наш список дат, мы форматируем его, используя DATE_FORMAT
и строку формата %M %Y
. Для обоих запросов вывод:
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
Демонстрация на dbfiddle