Для этого можно использовать рекурсивное общее табличное выражение:
with cte as (
select cast('2018-01-31' as date) EndOfMonth
union all
select eomonth(dateadd(month, 1, EndOfMonth))
from cte
where EndOfMonth < cast('2018-12-01' as date)
)
select * from cte
Элемент привязки запускается в последний день января 2018 г., а рекурсивный элемент добавляет 1 месяц на итерацию, используя eomonth()
для всегда возвращайте последний день месяца, пока не наступит декабрь 2018 года. При необходимости вы можете легко настроить дату начала и окончания.
Демонстрация на DB Fiddle
| EndOfMonth |
| :------------------ |
| 31/01/2018 00:00:00 |
| 28/02/2018 00:00:00 |
| 31/03/2018 00:00:00 |
| 30/04/2018 00:00:00 |
| 31/05/2018 00:00:00 |
| 30/06/2018 00:00:00 |
| 31/07/2018 00:00:00 |
| 31/08/2018 00:00:00 |
| 30/09/2018 00:00:00 |
| 31/10/2018 00:00:00 |
| 30/11/2018 00:00:00 |
| 31/12/2018 00:00:00 |
Редактировать
Как прокомментировал @squillman: если вы планируете создавать календарь на более чем 7 лет, то вам нужно добавить условие option(maxrecursion 0)
в конце запроса.
Как прокомментировал @ Ларну: производительность рекурсивного запроса падает, когда набор данных становится больше. Если вам нужно создать очень большой календарь (например, несколько столетий), тогда другие варианты лучше.
Наконец: если вы обнаруживаете, что в своих запросах вы повторяете генерацию календарных таблиц, вам следует рассмотреть материализацию календаря, ie его сохранение в реальной таблице базы данных, которое вы затем сможете join
в ваших запросах. Это широко используемое решение для проектирования баз данных, которое делает запросы проще и эффективнее. Вы можете использовать предложенные запросы для первоначальной подачи таблицы.