2010-06-21 14 views
32

Mam tabelę (MySQL), która przechwytuje próbki co n sekund. Tabela ma wiele kolumn, ale liczy się tylko dwa: znacznik czasu (typu TIMESTAMP) i licznik (typu INT).SELECT/GROUP BY - segmenty czasu (10 sekund, 30 sekund, itp.)

Co chciałbym zrobić, to uzyskać sumy i średnie z kolumny liczenia w różnych przedziałach czasowych. Na przykład mam próbki co 2 sekundy nagrane, ale chciałbym, aby suma kolumn zliczania dla wszystkich próbek była wyświetlana w oknie 10-sekundowym lub 30-sekundowym dla wszystkich próbek.

Oto przykład danych:

 
+---------------------+-----------------+ 
| 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 | 
+---------------------+-----------------+ 

Wyjście Chciałbym (na podstawie powyższych danych) powinien wyglądać następująco:

 
+---------------------+-----------------+ 
| 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 
+---------------------+-----------------+ 

Użyłem GROUP BY, żeby zebrać te numery na sekundę lub minutę, ale nie mogę wydawać się, aby dowiedzieć się składni, aby uzyskać podrzędne minuty lub zakres sekund polecenia GROUP BY działać poprawnie.

Przeważnie zamierzam używać tego zapytania do przesyłania danych z tej tabeli do innej tabeli.

Dzięki!

Odpowiedz

58

GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 30

lub powiedzieć z jakiegoś powodu chciał grupy je w odstępach 20-sekundowych byłoby DIV 20 itd. Aby zmienić granice między GROUP BY wartości można użyć

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

gdzie r jest literalną nieujemną liczbą całkowitą mniejszą niż 30. Tak więc

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

powinien podać sumy między hh: mm: 05 i hh: mm: 35 oraz między hh: mm: 35 a hh: mm + 1: 05.

+0

Idealnie! To * dokładnie * to, czego potrzebowałem! Wielkie dzięki! –

6

Próbowałem rozwiązania Hammerite w moim projekcie, ale nie działało dobrze tam, gdzie brakowało próbek z serii. Oto przykład kwerendy, która ma wybrać znacznik czasu (TS), nazwę użytkownika i średniej miary z metric_table i grupowych wyników przez odstępach czasowych 27-minutowych:

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 
; 

Uwaga: 27 minut (w wybranych) = 1620 sekund (w grupie), 2160 minut = 3 dni (to jest przedział czasowy)

Po uruchomieniu tego zapytania w odniesieniu do szeregu czasowego, w którym próbki były nieregularnie rejestrowane (innymi słowy: w przypadku dowolnego datownika nie było gwarancja znalezienia wartości miar dla wszystkich nazw użytkowników) wyniki nie były stemplowane zgodnie z interwałem (nie były umieszczane co 27 ​​minut). Podejrzewałem, że było to spowodowane tym, że min (ts) zwrócił znacznik czasu w niektórych grupach, który był większy niż oczekiwany poziom (interwał ts0 + i *). Zmodyfikowałem poprzednie zapytanie na to:

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 
; 

i działa dobrze nawet wtedy, gdy brakuje próbek. Myślę, że to dlatego, że gdy matematyka zostanie przesunięta w czasie selekcji, gwarantuje to, że ts1 dopasuje się do stopni czasowych.

+0

Dzięki za przedstawienie tego, pomogłeś mi bardzo! – citysurrounded

+0

Cudowne rzeczy! Wszystko, czego teraz potrzebuję, to sposób na nagranie wiersza "zero", gdy w tym czasie nie ma próbek ... –

+0

@DanielRhodes kiedykolwiek to wymyśliły? –

0

Bardzo dziwne, ale stosując rozwiązanie tutaj:

Average of data for every 5 minutes in the given times

Możemy zaproponować coś takiego:

select convert(
(min(dt_record) div 50)*50 - 20*((convert(min(dt_record), datetime) div 50) mod 2), 

datetime) jako dt, AVG (1das4hrz) od meteor-m2_msgi gdzie dt_record> = "2016-11-13 05:00:00" i dt_record < '2016-11-14 00:00:00' grupa przez konwersję (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, ponieważ 1/2 NORMALNY minut jest 30 sekund, podczas gdy 'format DATA INTEGER' przypuszczać nam podzielić przez 50

2

inne rozwiązanie.

Aby uzyskać średnią z dowolnych przedziałów czasu, możesz przekonwertować dt na znacznik czasu i grupować według modulo według przedziału czasu (7 sekund w przykładzie).

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); 

Aby pokazać, jak to działa, przygotowuję żądanie, pokazując obliczenia.

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 | 
+---------------------+-----+-----+------------+------+---------------------+----------+ 

Czy ktoś może zaproponować coś szybciej?

Powiązane problemy