我敢肯定有一些花哨的方法可以做到这一点,但我认为只需点击内置日历表可能是最简单的:
SELECT DISTINCT
min(calendar_date) OVER (PARTITION BY year_of_calendar, month_of_calendar) as start_of_month,
max(calendar_date) OVER (PARTITION BY year_of_calendar, month_of_calendar) as end_of_month
FROM sys_calendar.calendar
WHERE year_of_calendar BETWEEN 2016 and 2021
要在没有表引用的情况下执行此操作,它会变得有点难看。EXPAND ON
似乎是一条明显的路线,但如果 FROM 子句中没有表引用,则会出错。UNION
遇到同样的问题,但我们可以UNION
通过使用 cte 来作弊。EXPAND ON
更挑剔,为了欺骗它,我们可以劫持 Teradata 的JSON_TABLE
功能:
SELECT BEGIN(dt), PRIOR(END(dt))
FROM JSON_TABLE
(
ON (SELECT 1 as id, NEW JSON('{"startdate":"2016-01-01","enddate":"2021-12-31"}') jd)
USING
rowexpr('$')
colexpr('[{"jsonpath" : "$.startdate", "type" : "DATE"},
{"jsonpath" : "$.enddate", "type" : "DATE"}]')
) as jt(id, startdate, enddate)
EXPAND ON PERIOD(startdate, enddate) as dt BY ANCHOR MONTH_BEGIN
您也可以使用递归 CTE 来构建月份,这感觉不那么 hacky,但需要更长的时间来生成。
WITH startend AS
(
SELECT
DATE '2016-01-01' periodstartdate,
DATE '2021-12-31' AS periodenddate
)
,RECURSIVE months AS
(
SELECT periodstartdate,
periodenddate,
periodstartdate as monthstartdate,
1 as monthoffset
FROM startend
UNION ALL
SELECT periodstartdate,
periodenddate,
ADD_MONTHS(periodstartdate, monthoffset),
monthoffset + 1
FROM
months
WHERE monthoffset < months_between(periodenddate, periodstartdate)
)
SELECT monthstartdate, monthstartdate + INTERVAL '1' MONTH - INTERVAL '1' DAY as monthenddate from months;
如果有更优雅的方式来解决这个问题,我会非常感兴趣。如果没有dual
其他 RDBMS 中的序列生成,则构建没有表引用的数据集的选项非常有限。