我在PostgreSQL数据库中有一个表,其中包含日期和每天的总计数。
mydate total 2012-05-12 12 2012-05-14 8 2012-05-13 4 2012-05-12 12 2012-05-15 2 2012-05-17 1 2012-05-18 1 2012-05-21 1 2012-05-25 1
现在我需要获得给定日期范围的每周总数
防爆。我希望将每周总计从2012-05-01
提升到2012-05-31
。
我正在看这个输出:
2012-05-01 2012-05-07 0 2012-05-08 2012-05-14 36 2012-05-15 2012-05-22 5 2012-05-23 2012-05-29 1 2012-05-30 2012-05-31 0
答案 0 :(得分:3)
这适用于任何给定的日期范围:
CREATE FUNCTION f_tbl_weekly_sumtotals(_range_start date, _range_end date)
RETURNS TABLE (week_start date, week_end date, sum_total bigint)
LANGUAGE sql AS
$func$
SELECT w.week_start, w.week_end, COALESCE(sum(t.total), 0)
FROM (
SELECT week_start::date, LEAST(week_start::date + 6, _range_end) AS week_end
FROM generate_series(_range_start::timestamp
, _range_end::timestamp
, interval '1 week') week_start
) w
LEFT JOIN tbl t ON t.mydate BETWEEN w.week_start and w.week_end
GROUP BY w.week_start, w.week_end
ORDER BY w.week_start
$func$;
呼叫:
SELECT * FROM f_tbl_weekly_sumtotals('2012-05-01', '2012-05-31');
为方便起见,我将其包装在一个函数中,因此日期范围必须只提供一次。
子查询w
生成从给定日期范围的第一天开始的一系列周。上限的上限为LEAST
,以保持在给定日期范围的上限。
然后LEFT JOIN
到数据表(我的示例中为tbl
),以便在结果中保留所有周,即使没有找到数据行。< / p>
其余应该是显而易见的。 <{1}}在空周内输出COALESCE
而不是0
。
数据类型必须匹配,我假设NULL
和mydate date
缺少信息。 (total int
的{{1}}为sum()
。)
我对int
的具体用法的解释:
答案 1 :(得分:0)
使用此function
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;