SELECT / GROUP BY - отрезки времени (10 секунд, 30 секунд и т. Д.) - PullRequest
39 голосов
/ 21 июня 2010

У меня есть таблица (MySQL), которая захватывает выборки каждые n секунд.В таблице много столбцов, но для этого важны только два: отметка времени (типа TIMESTAMP) и счетчик (типа INT).

То, что я хотел бы сделать, это получить суммы и средние значения столбца подсчета за определенный промежуток времени.Например, я записываю выборки каждые 2 секунды, но мне хотелось бы, чтобы сумма столбца подсчета для всех выборок в 10-секундном или 30-секундном окне для всех выборок.

Вот пример данных:

+---------------------+-----------------+
| time_stamp          | count           |
+---------------------+-----------------+
| 2010-06-15 23:35:28 |               1 |
| 2010-06-15 23:35:30 |               1 |
| 2010-06-15 23:35:30 |               1 |
| 2010-06-15 23:35:30 |             942 |
| 2010-06-15 23:35:30 |             180 |
| 2010-06-15 23:35:30 |               4 |
| 2010-06-15 23:35:30 |              52 |
| 2010-06-15 23:35:30 |              12 |
| 2010-06-15 23:35:30 |               1 |
| 2010-06-15 23:35:30 |               1 |
| 2010-06-15 23:35:33 |            1468 |
| 2010-06-15 23:35:33 |             247 |
| 2010-06-15 23:35:33 |               1 |
| 2010-06-15 23:35:33 |              81 |
| 2010-06-15 23:35:33 |              16 |
| 2010-06-15 23:35:35 |            1828 |
| 2010-06-15 23:35:35 |             214 |
| 2010-06-15 23:35:35 |              75 |
| 2010-06-15 23:35:35 |               8 |
| 2010-06-15 23:35:37 |            1799 |
| 2010-06-15 23:35:37 |              24 |
| 2010-06-15 23:35:37 |              11 |
| 2010-06-15 23:35:37 |               2 |
| 2010-06-15 23:35:40 |             575 |
| 2010-06-15 23:35:40 |               1 |
| 2010-06-17 10:39:35 |               2 |
| 2010-06-17 10:39:35 |               2 |
| 2010-06-17 10:39:35 |               1 |
| 2010-06-17 10:39:35 |               2 |
| 2010-06-17 10:39:35 |               1 |
| 2010-06-17 10:39:40 |              35 |
| 2010-06-17 10:39:40 |              19 |
| 2010-06-17 10:39:40 |              37 |
| 2010-06-17 10:39:42 |              64 |
| 2010-06-17 10:39:42 |               3 |
| 2010-06-17 10:39:42 |              31 |
| 2010-06-17 10:39:42 |               7 |
| 2010-06-17 10:39:42 |             246 |
+---------------------+-----------------+

Вывод, который я хотел бы (основываясь на данных выше), должен выглядеть следующим образом:

+---------------------+-----------------+
| 2010-06-15 23:35:00 |               1 |  # This is the sum for the 00 - 30 seconds range
| 2010-06-15 23:35:30 |            7544 |  # This is the sum for the 30 - 60 seconds range
| 2010-06-17 10:39:35 |             450 |  # This is the sum for the 30 - 60 seconds range
+---------------------+-----------------+

Я использовал GROUP BY, чтобы собрать эти числа по секундам илиминуту, но я не могу понять синтаксис для правильной работы команд GROUP BY в течение минуты или диапазона секунд.

В основном я собираюсь использовать этот запрос для перехвата данных изэтот стол к другому столу.

Спасибо!

Ответы [ 4 ]

66 голосов
/ 21 июня 2010

GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 30

или, по какой-то причине, вы хотите сгруппировать их с 20-секундными интервалами, это будет DIV 20 и т. Д. Чтобы изменить границы между значениями GROUP BY, вы можете использовать

GROUP BY (UNIX_TIMESTAMP(time_stamp) + r) DIV 30

, где r - буквальное неотрицательное целое число меньше 30. Итак,

GROUP BY (UNIX_TIMESTAMP(time_stamp) + 5) DIV 30

должен давать вам суммы между чч: мм: 05 и чч: мм: 35 и между чч: мм: 35 и чч: мм + 1: 05.

6 голосов
/ 19 марта 2015

Я попробовал решение Hammerite в своем проекте, но оно не сработало там, где отсутствовали образцы из серии. Вот пример запроса, который должен выбрать метку времени (ts), имя пользователя и среднюю меру из metric_table и сгруппировать результаты по 27-минутным временным интервалам:

select 
    min(ts), 
    user_name, 
    sum(measure) / 27
from metric_table 
where 
    ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 

group by unix_timestamp(ts) div 1620, user_name 
order by ts, user_name
;

Примечание: 27 минут (в выбранном) = 1620 секунд (в группе по), 2160 минут = 3 дня (это временной диапазон)

Когда я запустил этот запрос для временного ряда, в котором выборки были записаны нерегулярно (другими словами: для любой данной временной отметки не было гарантии найти значения мер для всех имен пользователей), результаты не были отмечены в соответствии с интервалом были размещены не каждые 27 минут). Я подозреваю, что это произошло из-за того, что min (ts) возвращала временную отметку в некоторых группах, которая была больше ожидаемого минимума (интервал ts0 + i *). Я изменил предыдущий запрос на этот:

select 
    from_unixtime(unix_timestamp(ts) - unix_timestamp(ts) mod 1620) as ts1, 
    user_name, 
    sum(measure) / 27
from metric_table
where 
    ts between date_sub('2015-03-17 00:00:00', INTERVAL 2160 MINUTE) and '2015-03-17 00:00:00' 

group by ts1, user_name 
order by ts1, user_name
;

и работает нормально, даже если отсчеты отсутствуют. Я думаю, это потому, что как только математика времени перемещается для выбора, это гарантирует, что ts1 будет соответствовать временным шагам.

2 голосов
/ 14 ноября 2016

Другое решение.

Для усреднения по любому интервалу, который вам нравится, вы можете преобразовать dt в метку времени и сгруппировать по модулю по вашему интервалу (в примере 7 секунд).

select FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7
) as dt, avg(1das4hrz) from `meteor-m2_msgi`
where dt_record>='2016-11-13 05:00:00'
and dt_record < '2016-11-13 05:02:00'
group by FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7);

Чтобы показать, как это работает, я готовлю запрос, показываю расчеты.

select dt_record, minute(dt_record) as mm, SECOND(dt_record) as ss,
UNIX_TIMESTAMP(dt_record) as uxt, UNIX_TIMESTAMP(dt_record) mod 7 as ux7,
FROM_UNIXTIME(
    UNIX_TIMESTAMP(dt_record) - UNIX_TIMESTAMP(dt_record) mod 7) as dtsub,
column from `yourtable` where dt_record>='2016-11-13 05:00:00'
and dt_record < '2016-11-13 05:02:00';

+---------------------+--------------------+
| dt                  | avg(column)        |
+---------------------+--------------------+
| 2016-11-13 04:59:43 |  25434.85714285714 |
| 2016-11-13 05:00:42 |  5700.728813559322 |
| 2016-11-13 05:01:41 |  950.1016949152543 |
| 2016-11-13 05:02:40 |  4671.220338983051 |
| 2016-11-13 05:03:39 | 25468.728813559323 |
| 2016-11-13 05:04:38 |  43883.52542372881 |
| 2016-11-13 05:05:37 | 24589.338983050846 |
+---------------------+--------------------+


+---------------------+-----+-----+------------+------+---------------------+----------+
| dt_record           | mm  | ss  | uxt        | ux7  | dtsub               | column   |
+---------------------+------+-----+------------+------+---------------------+----------+
| 2016-11-13 05:00:00 |   0 |   0 | 1479002400 |    1 | 2016-11-13 04:59:59 |    36137 |
| 2016-11-13 05:00:01 |   0 |   1 | 1479002401 |    2 | 2016-11-13 04:59:59 |    36137 |
| 2016-11-13 05:00:02 |   0 |   2 | 1479002402 |    3 | 2016-11-13 04:59:59 |    36137 |
| 2016-11-13 05:00:03 |   0 |   3 | 1479002403 |    4 | 2016-11-13 04:59:59 |    34911 |     
| 2016-11-13 05:00:04 |   0 |   4 | 1479002404 |    5 | 2016-11-13 04:59:59 |    34911 |
| 2016-11-13 05:00:05 |   0 |   5 | 1479002405 |    6 | 2016-11-13 04:59:59 |    34911 |
| 2016-11-13 05:00:06 |   0 |   6 | 1479002406 |    0 | 2016-11-13 05:00:06 |    33726 |
| 2016-11-13 05:00:07 |   0 |   7 | 1479002407 |    1 | 2016-11-13 05:00:06 |    32581 |
| 2016-11-13 05:00:08 |   0 |   8 | 1479002408 |    2 | 2016-11-13 05:00:06 |    32581 |
| 2016-11-13 05:00:09 |   0 |   9 | 1479002409 |    3 | 2016-11-13 05:00:06 |    31475 |
+---------------------+-----+-----+------------+------+---------------------+----------+

Может кто-нибудь посоветовать что-нибудь быстрее?

0 голосов
/ 14 ноября 2016

Очень странно, но здесь используется решение:

Среднее значение данных за каждые 5 минут в указанное время

Мы можем предложить что-то вроде:

select convert(
              (min(dt_record) div 50)*50 - 20*((convert(min(dt_record), 
               datetime) div 50) mod 2), datetime)  as dt, 
       avg(1das4hrz) 
from `meteor-m2_msgi`
where dt_record>='2016-11-13 05:00:00'
       and dt_record < '2016-11-14 00:00:00' 
group by convert(dt_record, datetime) div 50;


select (
convert(
min(dt_record), datetime) div 50)*50 - 20*(
(convert(min(dt_record), datetime) div 50) mod 2
) as dt,
avg(column) from `your_table`
where dt_record>='2016-11-13 05:00:00'
and dt_record < '2016-11-14 00:00:00'
group by convert(dt_record, datetime) div 50;

50 - потому что 1/2 от NORMAL минута имеет 30 секунд, в то время как «ФОРМАТ ДАТЫ INTEGER» предполагает деление на 50

...