Ну, @bogdhan sahlean дал хорошее решение на основе множеств, но ограничивает значения до 2048, учитывая тип данных date
и datetime2
, для которого диапазон для года составляет 0001-01-01
до 9999-12-31
, от MSDN
Диапазон дат от 0001-01-01 до 9999-12-31
С 1 января по 31 декабря 9999 года CE
хотя это крайний случай, но стоит знать.Так как, если в один прекрасный день кто-то попытается спроецировать месяцы более 170 лет:)
Даже самые одобренные ответы не удовлетворяют некоторым крайним случаям (когда дата начала> дата окончания не будет показывать месяц даты окончания,также рекурсивный запрос не выполняется после 100 выполнений по умолчанию).А также использование рекурсивного cte для итерации, что является резким падением производительности при массовом использовании.
Теперь лучшим решением (IMHO) является использование таблицы календаря или таблицы подсчета для генерации месяцев между двумя датами.Если невозможно создать таблицу, есть лучшая альтернатива - использовать каскадный CTE Ицик Бен Ганса для создания таблицы чисел. ( здесь ) Что быстрее, нет логических, физических чтений, нет рабочего стола NADA
Вот код
DECLARE @start DATETIME2 = '00010101'
DECLARE @end DATETIME2 = '99991231'
;WITH lv0 AS (SELECT 0 g UNION ALL SELECT 0)
,lv1 AS (SELECT 0 g FROM lv0 a CROSS JOIN lv0 b) -- 4
,lv2 AS (SELECT 0 g FROM lv1 a CROSS JOIN lv1 b) -- 16
,lv3 AS (SELECT 0 g FROM lv2 a CROSS JOIN lv2 b) -- 256
,lv4 AS (SELECT 0 g FROM lv3 a CROSS JOIN lv3 b) -- 65,536
,lv5 AS (SELECT 0 g FROM lv4 a CROSS JOIN lv4 b) -- 4,294,967,296
,Tally (n) AS (SELECT 0 UNION SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM lv5)
SELECT DATENAME(YEAR,DATEADD(MONTH,N,@start)) AS [Year Part], DATENAME(MONTH,DATEADD(MONTH,n,@start)) AS [Month Part]
FROM Tally where N between 0 and DATEDIFF(mm,@start,@end)
ORDER BY n;
Примечание: я добавил SELECT 0
, чтобы начать числа с 0-й позиции
Производительность, показанная на моем ПК,
Метод Ицик
(затронуто 119988 строк)
Время выполнения SQL Server: время ЦП = 187 мс, истекшее время = 706 мс.Время анализа и компиляции SQL Server: время ЦП = 0 мс, истекшее время = 0 мс.
Одно из приведенных здесь рекурсивных решений, которое занимает время
(119988 строка (и) затронута) Таблица «Рабочий стол».Число сканирований 2, логическое чтение 719923, физическое чтение 0, чтение с опережением 0, чтение логического объекта 0, чтение с физического объекта 0, чтение с опережением 0.
Время выполнения SQL Server: время ЦП = 890мс, прошедшее время = 1069 мс.
Производительность между таблицей подсчета, таблицей календаря и таблицей номеров Ицик может немного отличаться, но работает как очарование для всего диапазона дат, который вы предоставляете.