幸い、PostgreSQLを使用しています。ウィンドウ関数generate_series()
はあなたの友達です。
テストケース
次のテストテーブル(あなた 提供する必要があります):
CREATE TABLE event(event_id serial, ts timestamp);
INSERT INTO event (ts)
SELECT generate_series(timestamp '2018-05-01'
, timestamp '2018-05-08'
, interval '7 min') + random() * interval '7 min';
7分ごとに1つのイベント(さらに0〜7分、ランダムに)。
基本的な解決策
このクエリは、任意の時間間隔のイベントをカウントします。例では17分:
WITH grid AS (
SELECT start_time
, lead(start_time, 1, 'infinity') OVER (ORDER BY start_time) AS end_time
FROM (
SELECT generate_series(min(ts), max(ts), interval '17 min') AS start_time
FROM event
) sub
)
SELECT start_time, count(e.ts) AS events
FROM grid g
LEFT JOIN event e ON e.ts >= g.start_time
AND e.ts < g.end_time
GROUP BY start_time
ORDER BY start_time;
-
クエリは最小および最大の
ts
を取得します ベーステーブルから完全な時間範囲をカバーします。代わりに任意の時間範囲を使用できます。 -
任意を提供する 時間間隔 必要に応じて。
-
すべてに対して1行を生成します タイムスロット。その間隔中にイベントが発生しなかった場合、カウントは
0
です。 。 -
必ず上限と下限を処理してください 正しく:
- タイムスタンプ間のSQLクエリからの予期しない結果
-
ウィンドウ関数
lead()
見過ごされがちな機能があります。先頭の行が存在しない場合のデフォルトを提供できます。'infinity'
を提供する 例では。それ以外の場合、最後の間隔は上限のNULL
で切り捨てられます 。
最小限の同等物
上記のクエリはCTEとlead()
を使用しています 冗長な構文。エレガントで理解しやすいかもしれませんが、少し高価です。これは、より短く、より速く、最小限のバージョンです:
SELECT start_time, count(e.ts) AS events
FROM (SELECT generate_series(min(ts), max(ts), interval '17 min') FROM event) g(start_time)
LEFT JOIN event e ON e.ts >= g.start_time
AND e.ts < g.start_time + interval '17 min'
GROUP BY 1
ORDER BY 1;
「先週15分ごと」の例`
そして、to_char()
でフォーマットします 。
SELECT to_char(start_time, 'YYYY-MM-DD HH24:MI'), count(e.ts) AS events
FROM generate_series(date_trunc('day', localtimestamp - interval '7 days')
, localtimestamp
, interval '15 min') g(start_time)
LEFT JOIN event e ON e.ts >= g.start_time
AND e.ts < g.start_time + interval '15 min'
GROUP BY start_time
ORDER BY start_time;
それでもORDER BY
およびGROUP BY
基になるタイムスタンプの値 、フォーマットされた文字列ではありません。それはより速く、より信頼性があります。
db<>ここでフィドル
実行カウントを生成する関連回答 時間枠全体:
- PostgreSQL:クエリの行数を「分単位」で実行