1

PostgreSQL データベースに、日付と 1 日あたりの合計数を含むテーブルがあります。

マイデート合計
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
4

2 に答える 2

4

これは、任意の日付範囲で機能します。

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');

主なポイント

  • 便宜上関数でラップしたので、日付範囲は 1 回だけ指定する必要があります。

  • サブクエリwは、指定された日付範囲の最初の日から始まる一連の週を生成します。上限LEASTは、指定された日付範囲の上限内に収まるように制限されます。

  • 次にLEFT JOIN、データ テーブル (tbl私の例では) に移動して、データ行が見つからない場合でも、すべての週を結果に保持します。

  • 残りは明らかなはずです。空の週の代わりCOALESCEに出力します。0NULL

  • データ型は一致する必要があるmydate dateと思いtotal intましたが、情報が不足しているためです。( のsum()intですbigint。)

  • 私の特定の使用法についての説明generate_series()

于 2012-05-15T09:28:10.090 に答える
0

この機能の使用

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;
于 2012-05-15T09:30:57.373 に答える