2

私はPostgreSQLデータベースを使用した一時的な集約のためのJava実装に取り​​組んでいます。

私のテーブルはこんな感じ

Value | Start      | Stop
(int) | (Date)     | (Date)
-------------------------------
1     | 2004-01-01 | 2010-01-01
4     | 2000-01-01 | 2008-01-01

したがって、この期間を視覚化するには:

                      ------------------------------
  ----------------------------------------
2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
  [        4         ][       5=4+1      ][    1   ]

私のアルゴリズムは、データの時間的集計を計算するようになりました。例:SUM():

Value | Start      | Stop
-------------------------------
4     | 2000-01-01 | 2004-01-01
5     | 2004-01-01 | 2008-01-01
1     | 2008-01-01 | 2010-01-01

得られた結果をテストするために、PostgreSQLを使用してデータを直接クエリしたいと思います。この問題を解決する簡単な方法はまだありません。ただし、同じ結果を得る方法は確かにあります。集計Count、Max、Min、Sum、およびAverageがサポートされている必要があります。私は悪い解決策や遅い解決策を気にしません、それはただうまくいく必要があります。

これまでに見つけた、同様に機能するはずのクエリは次のとおりです。

select count(*), ts, te
from ( checkout a normalize checkout b using() ) checkoutNorm
group by ts, te;

私の養子縁組は次のようになります。

select count(*), start, stop
from ( myTable a normalize myTable b using() ) myTableNorm
group by start, stop;

ただし、エラーが報告されERROR: syntax error at or near "normalize" -- LINE 2: from ( ndbs_10 a normalize ndbs_10 b using() ) ndbsNormました。

誰かがこの問題の解決策を持っていますか?それが機能する限り、上記のクエリに基づく必要はありません。どうもありがとう。

4

1 に答える 1

2

あなたの質問は本当に理解するのが難しかったです。しかし、私はそれを理解したと思います。
のランニングサムが必要ですvaluestart値は、期間とstop期間の間でのみ適用されます。したがって、それらはその期間の初めに追加され、最後に差し引かれる必要があります。
さらに、合計が有効な結果の期間の開始と終了が必要です。
それはそれをするべきです:

-- DROP SCHEMA x CASCADE;
CREATE SCHEMA x;
CREATE TABLE x.tbl(val int, start date, stop date);
INSERT INTO x.tbl VALUES
 (4 ,'2000-01-01' ,'2008-01-01')
,(7 ,'2001-01-01' ,'2009-01-01')
,(1 ,'2004-01-01' ,'2010-01-01')
,(2 ,'2005-01-01' ,'2006-01-01');

WITH a AS (
    SELECT start as ts, val FROM x.tbl
    UNION  ALL
    SELECT stop, val * (-1) FROM x.tbl
    ORDER  BY 1, 2)
SELECT sum(val) OVER w AS val_sum
      ,ts AS start
      ,lead(ts) OVER w AS stop
FROM   a
WINDOW w AS (ORDER BY ts)
ORDER  BY ts;

val_sum |   start    |    stop
--------+------------+------------
      4 | 2000-01-01 | 2001-01-01
     11 | 2001-01-01 | 2004-01-01
     12 | 2004-01-01 | 2005-01-01
     14 | 2005-01-01 | 2006-01-01
     12 | 2006-01-01 | 2008-01-01
      8 | 2008-01-01 | 2009-01-01
      1 | 2009-01-01 | 2010-01-01
      0 | 2010-01-01 |

リクエスト後に編集

要求されたすべての集計関数の場合:

SELECT period
      ,val_sum
      ,val_count
      ,val_sum::float /val_count AS val_avg
      ,(SELECT min(val) FROM x.tbl WHERE start < y.stop AND stop > y.start) AS val_min
      ,(SELECT max(val) FROM x.tbl WHERE start < y.stop AND stop > y.start) AS val_max
      ,start
      ,stop
FROM   (
    WITH a AS (
         SELECT start as ts, val, 1 AS c FROM x.tbl
         UNION  ALL
         SELECT stop, val, -1 FROM x.tbl
         ORDER  BY 1, 2)
    SELECT count(*) OVER w AS period
          ,sum(val*c) OVER w AS val_sum
          ,sum(c) OVER w AS val_count
          ,ts AS start
          ,lead(ts) OVER w AS stop
    FROM   a
    WINDOW w AS (ORDER BY ts)
    ORDER  BY ts
    ) y
WHERE stop IS NOT NULL;

 period | val_sum | val_count | val_avg | val_min | val_max |   start    |    stop
--------+---------+-----------+---------+---------+---------+------------+------------
      1 |       4 |         1 |       4 |       4 |       4 | 2000-01-01 | 2001-01-01
      2 |      11 |         2 |     5.5 |       4 |       7 | 2001-01-01 | 2004-01-01
      3 |      12 |         3 |       4 |       1 |       7 | 2004-01-01 | 2005-01-01
      4 |      14 |         4 |     3.5 |       1 |       7 | 2005-01-01 | 2006-01-01
      5 |      12 |         3 |       4 |       1 |       7 | 2006-01-01 | 2008-01-01
      6 |       8 |         2 |       4 |       1 |       7 | 2008-01-01 | 2009-01-01
      7 |       1 |         1 |       1 |       1 |       1 | 2009-01-01 | 2010-01-01

min()おそらく最適化することもmaxできますが、それで十分です。ご覧のとおり、 CTE(WITH句)とサブクエリは交換可能です。

于 2011-11-07T16:48:22.220 に答える