使用此功能
CREATE OR REPLACE FUNCTION last_day(date)
RETURNS date AS
$$
SELECT (date_trunc('MONTH', $1) + INTERVAL '1 MONTH - 1 day')::date;
$$ LANGUAGE 'sql' IMMUTABLE STRICT;
AND generate_series(从 8.4 开始)我们可以创建日期分区。
SELECT wk.wk_start,
CAST(
CASE (extract(month from wk.wk_start) = extract(month from wk.wk_start + interval '6 days'))
WHEN true THEN wk.wk_start + interval '6 days'
ELSE last_day(wk.wk_start)
END
AS date) AS wk_end
FROM
(SELECT CAST(generate_series('2012-05-01'::date,'2012-05-31'::date,interval '1 week') AS date) AS wk_start) AS wk;
然后把它和数据放在一起
CREATE TABLE my_tab(mydate date,total integer);
INSERT INTO my_tab
values
('2012-05-12'::date,12),
('2012-05-14'::date,8),
('2012-05-13'::date,4),
('2012-05-12'::date,12),
('2012-05-15'::date,2),
('2012-05-17'::date,1),
('2012-05-18'::date,1),
('2012-05-21'::date,1),
('2012-05-25'::date,1);
WITH month_by_week AS
(SELECT wk.wk_start,
CAST(
CASE (extract(month from wk.wk_start) = extract(month from wk.wk_start + interval '6 days'))
WHEN true THEN wk.wk_start + interval '6 days'
ELSE last_day(wk.wk_start)
END
AS date) AS wk_end
FROM
(SELECT CAST(generate_series('2012-05-01'::date,'2012-05-31'::date,interval '1 week') AS date) AS wk_start) AS wk
)
SELECT month_by_week.wk_start,
month_by_week.wk_end,
SUM(COALESCE(mt.total,0))
FROM month_by_week
LEFT JOIN my_tab mt ON mt.mydate BETWEEN month_by_week.wk_start AND month_by_week.wk_end
GROUP BY month_by_week.wk_start,
month_by_week.wk_end
ORDER BY month_by_week.wk_start;