Generate series of week intervals for given month
在Postgres 9.1数据库中,我试图在给定月份生成一系列周,但有一些限制。 我需要所有星期一的星期一开始,并在他们开始或结束另一个月时被削减。
例:
对于2013年2月,我想生成一个这样的系列:
1 2 3 4 5 6 7 | START ------------------------ 2013-02-01 00:00:00+00 2013-02-04 00:00:00+00 2013-02-11 00:00:00+00 2013-02-18 00:00:00+00 2013-02-25 00:00:00+00 |
我现在的查询看起来像这样:
1 2 3 | SELECT GREATEST(date_trunc('week', dates.d), date_trunc('month',dates.d)) AS START FROM generate_series(to_timestamp(1359676800),to_timestamp(1362095999), '1 week') AS dates(d) |
这个查询让我获得了前4个星期,但它从25日开始错过了一周。 上周有可能上场吗?
1 2 3 4 5 | 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; |
此变体不需要子选择
-
在
date_trunc('week', ...) 之前的第一天添加6天,以计算该月的第一个星期一。 -
添加1个月并在
date_trunc('week', ...) 之前减去1天以获取该月的最后一个星期一。
这可以方便地填充到单个interval 表达式中:'1 month - 1 day' -
UNION (不是UNION ALL )添加它的月份的第一天,除非它已经包含在星期一。 -
请注意,
date +interval 会产生timestamp ,这是此处的最佳值。详细说明:- 生成PostgreSQL中两个日期之间的时间序列
自动化
您可以在CTE中提供日期系列的开头:
1 2 3 4 5 6 7 | 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函数,以方便重复调用:
1 2 3 4 5 6 7 8 9 10 | 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; |
呼叫:
1 | SELECT * FROM f_week_starts_this_month('2013-02-01'); |
您可以将该日期传递给该月的第一天,但??它适用于任何日期。您是第一天和下个月的所有星期一。
1 2 3 4 5 | SELECT greatest(date_trunc('week', dates.d), date_trunc('month',dates.d)) AS START FROM generate_series('2013-02-01'::DATE, '2013-02-28', '1 day') AS dates(d) GROUP BY 1 ORDER BY 1 |