Группировать по интервалам данных

У меня есть одна таблица, в которой хранится использование полосы пропускания в сети за определенный период времени. Один столбец будет содержать дату и время (первичный ключ), а другой столбец будет записывать пропускную способность. Данные записываются каждую минуту. У нас будут другие столбцы, записывающие другие данные в этот момент времени.

Если пользователь запрашивает данные с 15-минутными интервалами (в течение 24-часового периода с учетом даты начала и окончания), возможно ли с помощью одного запроса получить требуемые данные или мне нужно будет написать хранимую процедуру/курсор для этого ? Затем пользователи могут запрашивать данные с 5-минутными интервалами и т. д.

Я, скорее всего, буду использовать Postgres, но есть ли другие варианты NOSQL, которые были бы лучше?

Любые идеи?


person JD.    schedule 27.09.2012    source источник


Ответы (2)


WITH t AS (
   SELECT ts, (random()*100)::int AS bandwidth
   FROM   generate_series('2012-09-01', '2012-09-04', '1 minute'::interval) ts
   )

SELECT date_trunc('hour', ts) AS hour_stump
      ,(extract(minute FROM ts)::int / 15) AS min15_slot
      ,count(*) AS rows_in_timeslice               -- optional
      ,sum(bandwidth) AS sum_bandwidth
FROM   t
WHERE  ts >= '2012-09-02 00:00:00+02'::timestamptz -- user's time range
AND    ts <  '2012-09-03 00:00:00+02'::timestamptz -- careful with borders 
GROUP  BY 1, 2
ORDER  BY 1, 2;

CTE t предоставляет данные, которые могут содержаться в вашей таблице: один отметка времени ts в минуту с числом bandwidth. (Вам не нужна эта часть, вместо этого вы работаете со своей таблицей.)

Вот очень похожее решение для очень похожего вопроса - с подробным объяснением того, как работает эта конкретная агрегация:

Вот аналогичное решение аналогичного вопроса, касающегося текущих сумм - с подробным объяснением и ссылками на различные используемые функции:

Дополнительный вопрос в комментарии

WITH -- same as above ...

SELECT DISTINCT ON (1,2)
       date_trunc('hour', ts) AS hour_stump
      ,(extract(minute FROM ts)::int / 15) AS min15_slot
      ,bandwidth AS bandwith_sample_at_min15
FROM   t
WHERE  ts >= '2012-09-02 00:00:00+02'::timestamptz
AND    ts <  '2012-09-03 00:00:00+02'::timestamptz
ORDER  BY 1, 2, ts DESC;

Извлекает одну неагрегированную выборку за 15-минутный интервал из последней доступной строки в окне. Это будет 15-я минута, если ряд не пропущен. Ключевыми частями являются DISTINCT ON и ORDER BY.
Подробнее об используемой технике здесь:

person Erwin Brandstetter    schedule 27.09.2012
comment
Большое спасибо. Время учиться, я понятия не имел, что это вообще возможно. - person JD.; 27.09.2012
comment
Как получить фактическое значение на границе 15-й минуты, а не сумму (пропускную способность)? - person JD.; 27.09.2012
comment
@JD: определите на границе 15-й минуты. За минуту до или после? И вы имеете в виду неагрегированное значение из этой единственной строки, верно? - person Erwin Brandstetter; 27.09.2012

select
    date_trunc('hour', d) + 
    (((extract(minute from d)::integer / 5 * 5)::text) || ' minute')::interval
    as "from",
    date_trunc('hour', d) + 
    ((((extract(minute from d)::integer / 5 + 1) * 5)::text) || ' minute')::interval
    - '1 second'::interval
    as "to",
    sum(random() * 1000) as bandwidth
from 
    generate_series('2012-01-01', '2012-01-31', '1 minute'::interval) s(d)
group by 1, 2
order by 1, 2
;

Тот за 5 минут колеблется. 15 минут делим на 15.

person Clodoaldo Neto    schedule 27.09.2012
comment
Вау, спасибо, но с чего мне начать? generate_series() является? Как выглядит таблица? Извините, я довольно новичок в PostGres, поэтому, пожалуйста, потерпите меня. - person JD.; 27.09.2012
comment
@JD: Программное обеспечение называется PostgreSQL или Postgres для краткости. Подробности здесь. руководство по PostgreSQL превосходного качества. Перейдите по ссылкам (в соответствующих ответах, на которые я ссылаюсь в своем ответе!) Для получения подробной информации и глубоких ссылок на руководство. - person Erwin Brandstetter; 27.09.2012
comment
@Clodoaldo: Оказывается, в вашем ответе уже есть большая часть того, что я опубликовал, за исключением объяснений. +1 за первое место. - person Erwin Brandstetter; 27.09.2012