Группировать по интервалам данных
У меня есть одна таблица, в которой хранится информация о пропускной способности сети в течение определенного периода времени. Один столбец будет содержать дату и время (первичный ключ), а другой столбец будет записывать пропускную способность. Данные записываются каждую минуту. У нас будут другие столбцы, записывающие другие данные в этот момент времени.
Если пользователь запрашивает данные с 15-минутными интервалами (в течение 24-часового периода с учетом начальной и конечной даты), возможно ли с помощью одного запроса получить необходимые мне данные или мне нужно написать хранимую процедуру / курсор для этого? Затем пользователи могут запрашивать данные 5-минутных интервалов и т. Д.
Я, скорее всего, буду использовать Postgres, но есть ли другие варианты NOSQL, которые были бы лучше?
Есть идеи?
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
,
Больше информации об используемой технике здесь:
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.