为给定月份生成一系列周间隔



在Postgres 9.1数据库中,我试图为给定的月份生成一系列周,但有一些限制。我需要整个星期从周一开始,然后在下个月开始或结束时被裁掉。

示例:

2013年2月,我想生成一个这样的系列:

         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

我现在的查询如下:

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日开始的一周。有可能赶上最后一周吗?

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;

此变体不需要子选择GREATESTGROUP BY,只生成所需的行。更简单、更快。它比UNION一排便宜。

  • date_trunc('week', ...)之前,将6天添加到该月的第一天,以计算该月的第一个星期一。

  • date_trunc('week', ...)之前加1个月,减去1天,得到该月的最后一个星期一
    这可以方便地填充到单个interval表达式中:'1 month - 1 day'

  • UNION(而非UNION ALL(要添加它的月份的第一天,除非它已包含为星期一。

  • 注意,date+interval导致timestamp,这在这里是最优的。详细说明:

    • 在PostgreSQL中生成两个日期之间的时间序列

自动化

您可以在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');

您可以将日期传给本月的第一天,但它适用于任何日期。你的第一天和下个月的所有星期一。

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

相关内容

  • 没有找到相关文章

最新更新