Edd*_*die 10 sql postgresql time-series weekday generate-series
在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
Run Code Online (Sandbox Code Playgroud)
我现在的查询看起来像这样:
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)
Run Code Online (Sandbox Code Playgroud)
这个查询让我获得了前4个星期,但它从25日开始错过了一周.上周有可能上场吗?
Erw*_*ter 11
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;
Run Code Online (Sandbox Code Playgroud)
此变体不需要子选择,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;
Run Code Online (Sandbox Code Playgroud)
或者将它包装成一个简单的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;
Run Code Online (Sandbox Code Playgroud)
呼叫:
SELECT * FROM f_week_starts_this_month('2013-02-01');
Run Code Online (Sandbox Code Playgroud)
您可以将该日期传递给该月的第一天,但它适用于任何日期.您是第一天和下个月的所有星期一.
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
Run Code Online (Sandbox Code Playgroud)