Временная агрегация в PostgreSQL - PullRequest
1 голос
/ 07 ноября 2011

Я работаю над реализацией Java для временного агрегирования с использованием базы данных PostgreSQL.

Мой стол выглядит так

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.

У кого-нибудь есть решение этой проблемы? Он не должен быть основан на вышеупомянутом запросе, пока он работает. Большое спасибо.

1 Ответ

2 голосов
/ 07 ноября 2011

Ваш вопрос было действительно трудно понять. Но я думаю Я понял это.
Вы хотите, чтобы текущая сумма превысила value. Значения применимы только между start и 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) и подзапросы являются взаимозаменяемыми, как вы можете видеть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...