テストケース:
CREATE TABLE tbl (date date, email text);
INSERT INTO tbl VALUES
('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-03', '[email protected]')
, ('2012-01-04', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]`')
;
クエリ-エントリがtbl
に存在する日のみを返します :
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN t.date - 2 AND t.date -- period of 3 days
) AS dist_emails
FROM tbl t
WHERE date BETWEEN '2012-01-01' AND '2012-01-06'
GROUP BY 1
ORDER BY 1;
または-すべての日を返します その日の行がない場合でも、指定された範囲内:
SELECT date
,(SELECT count(DISTINCT email)
FROM tbl
WHERE date BETWEEN g.date - 2 AND g.date
) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date);
db<>ここでフィドル
結果:
day | dist_emails
-----------+------------
2012-01-01 | 3
2012-01-02 | 3
2012-01-03 | 3
2012-01-04 | 3
2012-01-05 | 1
2012-01-06 | 2
この音 最初はウィンドウ関数の仕事のようでしたが、適切なウィンドウフレームを定義する方法が見つかりませんでした。また、ドキュメントごとに:
集計ウィンドウ関数は、通常の集計関数とは異なり、
DISTINCT
を許可しません またはORDER BY
関数の引数リスト内で使用されます。
そこで、代わりに相関サブクエリを使用して解決しました。それが最も賢い方法だと思います。
ところで、「上記の日付から3日前まで」は、 4の期間になります。 日々。あなたの定義はそこで矛盾しています。
少し短いですが、数日間は遅くなります:
SELECT g.date, count(DISTINCT email) AS dist_emails
FROM (SELECT generate_series(timestamp '2012-01-01'
, timestamp '2012-01-06'
, interval '1 day')::date) AS g(date)
LEFT JOIN tbl t ON t.date BETWEEN g.date - 2 AND g.date
GROUP BY 1
ORDER BY 1;
関連:
- PostgreSQLで2つの日付間の時系列を生成する
- 時間間隔のある行のローリングカウント