その分までの行の合計数を毎分クエリする必要があります。
これまでに達成できた最善の方法ではうまくいきません。各分までの合計カウントではなく、1 分あたりのカウントを返します。
SELECT COUNT(id) AS count
, EXTRACT(hour from "when") AS hour
, EXTRACT(minute from "when") AS minute
FROM mytable
GROUP BY hour, minute
その分までの行の合計数を毎分クエリする必要があります。
これまでに達成できた最善の方法ではうまくいきません。各分までの合計カウントではなく、1 分あたりのカウントを返します。
SELECT COUNT(id) AS count
, EXTRACT(hour from "when") AS hour
, EXTRACT(minute from "when") AS minute
FROM mytable
GROUP BY hour, minute
SELECT DISTINCT
date_trunc('minute', "when") AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY 1;
を使用するdate_trunc()
と、必要なものが正確に返されます。
スライスid
を細かくしたいので、クエリに含めないでください。GROUP BY
count()
通常、単純な集計関数として使用されます。OVER
句を追加すると、ウィンドウ関数になります。ウィンドウ定義を省略します。すべての行PARTITION BY
で実行中のカウントが必要です。デフォルトでは、 で定義されているように、現在の行の最初の行から最後のピアまでカウントされます。マニュアル:ORDER BY
デフォルトのフレーミング オプションは です
RANGE UNBOUNDED PRECEDING
。これは と同じRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
です。を使用ORDER BY
すると、フレームが、パーティションの開始から現在の行の最後のORDER BY
ピアまでのすべての行になるように設定されます。
そして、それはまさにあなたが必要としているものです。
count(*)
ではなく使用しcount(id)
ます。あなたの質問(「行数」)により適しています。通常、 よりわずかに高速ですcount(id)
。そして、それは であると仮定するかもしれませんid
がNOT NULL
、それは質問で指定されていないためcount(id)
、厳密に言えば間違ってcount(id)
います。
GROUP BY
同じクエリ レベルでスライスを分割することはできません。集計関数はウィンドウ関数の前にcount(*)
適用されます。ウィンドウ関数は、このように 1 分あたり 1 行しか表示しません。
ただし、はウィンドウ関数の後に適用されるSELECT DISTINCT
ため、可能です。DISTINCT
ORDER BY 1
ここの省略形ORDER BY date_trunc('minute', "when")
です。
1
リストの最初の式への位置参照参照SELECT
です。
to_char()
結果をフォーマットする必要がある場合に使用します。お気に入り:
SELECT DISTINCT
to_char(date_trunc('minute', "when"), 'DD.MM.YYYY HH24:MI') AS minute
, count(*) OVER (ORDER BY date_trunc('minute', "when")) AS running_ct
FROM mytable
ORDER BY date_trunc('minute', "when");
SELECT minute, sum(minute_ct) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) sub
ORDER BY 1;
上記とよく似ていますが、次のとおりです。
サブクエリを使用して、1 分あたりの行数を集計およびカウントします。このようにDISTINCT
して、outer なしで毎分 1 行を取得しSELECT
ます。
ウィンドウ集計関数として使用sum()
して、サブクエリからのカウントを合計します。
これは、1 分あたりの行数が多いため、大幅に高速であることがわかりました。
@GabiMe はコメントで、イベントが発生しなかったもの (ベース テーブルに行がないもの) を含め、時間枠内のすべて の行を1 行取得する方法を尋ねました。minute
SELECT DISTINCT
minute, count(c.minute) OVER (ORDER BY minute) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (SELECT date_trunc('minute', "when") FROM tbl) c(minute) USING (minute)
ORDER BY 1;
generate_series()
サブクエリからの集計値に直接基づいて、最初のイベントと最後のイベントの間の時間枠で 1 分ごとに行を生成します。
LEFT JOIN
分とカウントに切り捨てられたすべてのタイムスタンプ。NULL
値 (行が存在しない場合) は実行中のカウントに加算されません。
CTE の場合:
WITH cte AS (
SELECT date_trunc('minute', "when") AS minute, count(*) AS minute_ct
FROM tbl
GROUP BY 1
)
SELECT m.minute
, COALESCE(sum(cte.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(min(minute), max(minute), interval '1 min')
FROM cte
) m(minute)
LEFT JOIN cte USING (minute)
ORDER BY 1;
繰り返しますが、最初のステップで 1 分あたりの行を集計してカウントしますDISTINCT
。
とは異なりcount()
、sum()
返品できNULL
ます。デフォルトは0
withCOALESCE
です。
Postgres 9.1 - 9.4 でテストしたいくつかのバリアントの中で、サブクエリを使用したこのバージョンの多くの行とインデックスが最速でした。"when"
SELECT m.minute
, COALESCE(sum(c.minute_ct) OVER (ORDER BY m.minute), 0) AS running_ct
FROM (
SELECT generate_series(date_trunc('minute', min("when"))
, max("when")
, interval '1 min')
FROM tbl
) m(minute)
LEFT JOIN (
SELECT date_trunc('minute', "when") AS minute
, count(*) AS minute_ct
FROM tbl
GROUP BY 1
) c USING (minute)
ORDER BY 1;