SELECT generate_series(date_trunc('week', date '2013-02-01' + interval '6 days')
, date_trunc('week', date '2013-02-01' + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION SELECT date '2013-02-01'
ORDER BY 1;
此变体不需要子选择,GREATEST
或者GROUP BY
只生成所需的行。更简单,更快。UNION
一排更便宜。
将前一个月的第一天加上 6 天来date_trunc('week', ...)
计算该月的第一个星期一。
加 1 个月并减去 1 天前date_trunc('week', ...)
得到该月的最后一个星期一。
这可以方便地填充到单个interval
表达式中:'1 month - 1 day'
UNION
(不是 UNION ALL
)每月的第一天添加它,除非它已经包含在星期一。
请注意,date
+interval
导致timestamp
,这是此处的最佳值。详细解释:
自动化
您可以在 CTE 中提供日期系列的开始:
WITH t(d) AS (SELECT date '2013-02-01') -- enter 1st of month once
SELECT generate_series(date_trunc('week', d + interval '6 days')
, date_trunc('week', d + interval '1 month - 1 day')
, interval '1 week')::date AS day
FROM t
UNION SELECT d FROM t
ORDER BY 1;
或者将其包装成一个简单的 SQL 函数,以方便重复调用:
CREATE OR REPLACE FUNCTION f_week_starts_this_month(date)
RETURNS SETOF date AS
$func$
SELECT generate_series(date_trunc('week', $1 + interval '6 days')
, date_trunc('week', $1 + interval '1 month - 1 day')
, interval '1 week')::date AS day
UNION
SELECT $1
ORDER BY 1
$func$ LANGUAGE sql IMMUTABLE;
称呼:
SELECT * FROM f_week_starts_this_month('2013-02-01');
您将通过该月的第一天的日期,但它适用于任何日期。您是下个月的第一天和所有星期一。