2012-06-29 10 views
6

1分ごとにすべてのデータをカウントする次のクエリがあります。テーブルの3行ごとに合計

$sql= "SELECT COUNT(*) AS count, date_trunc('minute', date) AS momento 
FROM p WHERE fk_id_b=$id_b GROUP BY date_trunc('minute', date) 
ORDER BY momento ASC"; 

私がする必要があるのは、過去2分のカウントで各行のカウントの合計を得ることです。

For example with the result of the $sql query above 
|-------date---------|----count----| 
|2012-06-21 05:20:00 |  12  | 
|2012-06-21 05:21:00 |  14  | 
|2012-06-21 05:22:00 |  10  | 
|2012-06-21 05:23:00 |  20  | 
|2012-06-21 05:24:00 |  25  | 
|2012-06-21 05:25:00 |  30  | 
|2012-06-21 05:26:00 |  10  | 

I want this result: 

|-------date---------|----count----| 
|2012-06-21 05:20:00 |  12  | 
|2012-06-21 05:21:00 |  26  |  12+14 
|2012-06-21 05:22:00 |  36  |  12+14+10 
|2012-06-21 05:23:00 |  44  |  14+10+20 
|2012-06-21 05:24:00 |  55  |  10+20+25 
|2012-06-21 05:25:00 |  75  |  20+25+30 
|2012-06-21 05:26:00 |  65  |  25+30+10 
+0

にこの上でより多くを見つけることができます。あなたのアプリケーションは仕事をすることはできませんか?とにかく行をフェッチする必要があります。同じループで行をフェッチできます。 – Searle

+0

@Parth Bhatt:あなたが承認した編集は明らかに別の質問をしています。このような編集は承認しないでください。 – interjay

+0

@interjay:私の間違い申し訳ありませんが、私はそれを間違った方法で解釈しました。 –

答えて

10

は、これは(SQL Fiddleにも)lag() window functionととてもトリッキーではありません。

CREATE TABLE t ("date" timestamptz, "count" int4); 
INSERT INTO t VALUES 
('2012-06-21 05:20:00',12), 
('2012-06-21 05:21:00',14), 
('2012-06-21 05:22:00',10), 
('2012-06-21 05:23:00',20), 
('2012-06-21 05:24:00',25), 
('2012-06-21 05:25:00',30), 
('2012-06-21 05:26:00',10); 

SELECT *, 
    "count" 
    + coalesce(lag("count", 1) OVER (ORDER BY "date"), 0) 
    + coalesce(lag("count", 2) OVER (ORDER BY "date"), 0) AS "total" 
    FROM t; 
  1. これらは予約語がそうであるように、私は、二重引用符で囲まれたdatecount列をしました。
  2. lag(field, distance)私にfielddistance行の値を返します。したがって、最初の関数は前の行の値を返し、2番目の呼び出しは前の値を返します。
  3. coalesce()lag()関数からNULL結果を回避するために必要とされる(最初の行のクエリではない「以前の」1はありません、ので、それはNULLだ)、それ以外totalNULLになります。
+0

優秀!私はウィンドウ関数の概念が大好きですが、それらを使うのを忘れています。 upvote :-) – Searle

+0

+1を適切な解決策にしてください。コメントは十分ではないので、私は答えを書いた。 –

9

@vyegorov's answerが主にカバーしています。しかし、私はコメントに収まるよりも多くの不満を持っています。

  1. は、識別子のすべてのでとしてdateようreserved wordscountを使用しないでください。 PostgreSQLでは、これらの2つのキーワードをすべてのSQL標準以外の識別子として使用できます。しかしそれはまだ悪い習慣です。 のように二重引用符で囲んだものを識別子として使うこともできます。"; DELETE FROM tbl;"でもそれは良い考えではありません。 timestampの名前"date"はその上に誤解を招きます。

  2. データ型が正しくありません。例は、timestamptzではなく、timestampと表示されます。ここで違いはありませんが、それでも誤解を招くことはありません。

  3. COALESCE()は必要ありません。

ビルこのセットアップに:window functions lag() and lead()を使用すると、3番目のパラメータとしてデフォルト値を提供することができますすることができます

CREATE TABLE tbl (ts timestamp, ct int4); 
INSERT INTO tbl VALUES 
    ('2012-06-21 05:20:00', 12) 
, ('2012-06-21 05:21:00', 14) 
, ('2012-06-21 05:22:00', 10) 
, ('2012-06-21 05:23:00', 20) 
, ('2012-06-21 05:24:00', 25) 
, ('2012-06-21 05:25:00', 30) 
, ('2012-06-21 05:26:00', 10); 

問合せ:まだ

SELECT ts, ct + lag(ct, 1, 0) OVER (ORDER BY ts) 
       + lag(ct, 2, 0) OVER (ORDER BY ts) AS total 
FROM tbl; 

またはより良いです:窓集約関数として単一のsum()を使用するwi tha a custom window frame

SELECT ts, sum(ct) OVER (ORDER BY ts ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) 
FROM tbl; 

同じ結果です。
関連:

+0

'lag' /' lead'のデフォルト値は素晴らしいです! – vyegorov

10

ここでは、現在およびN前の行からの値の合計のためのより一般的な解決策は、(N =あなたのケースでは2)です。

SELECT "date", 
sum("count") OVER (order by "date" ROWS BETWEEN 2 preceding AND current row) 
FROM t 
ORDER BY "date"; 

Nを「無制限」に変更できます。このアプローチでは、アプリ内のパラメータ「過去N分のカウント」を得る機会が与えられます。また、境界外の場合はデフォルト値を処理する必要はありません。

あなたは、SQLと非常にトリッキーなPostgreSQLのドキュメント(4.2.8. Window Function Calls

+0

これは受け入れられた回答よりも優れた解決策です – user2259664

関連する問題