Mam pewne problemy z poleceniami mySQL, które chcę wykonać.
SELECT a.timestamp, name, count(b.name)
FROM time a, id b
WHERE a.user = b.user
AND a.id = b.id
AND b.name = 'John'
AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00'
GROUP BY a.timestamp
To jest moje aktualne oświadczenie wyjściowe.
timestamp name count(b.name)
------------------- ---- -------------
2010-11-16 10:32:22 John 2
2010-11-16 10:35:12 John 7
2010-11-16 10:36:34 John 1
2010-11-16 10:37:45 John 2
2010-11-16 10:48:26 John 8
2010-11-16 10:55:00 John 9
2010-11-16 10:58:08 John 2
Jak pogrupować je w wyniki co 5 minut?
Chcę, żeby moja twórczość była taka
timestamp name count(b.name)
------------------- ---- -------------
2010-11-16 10:30:00 John 2
2010-11-16 10:35:00 John 10
2010-11-16 10:40:00 John 0
2010-11-16 10:45:00 John 8
2010-11-16 10:50:00 John 0
2010-11-16 10:55:00 John 11
Odpowiedzi:
Działa to z każdym interwałem.
PostgreSQL
SELECT TIMESTAMP WITH TIME ZONE 'epoch' + INTERVAL '1 second' * round(extract('epoch' from timestamp) / 300) * 300 as timestamp, name, count(b.name) FROM time a, id WHERE … GROUP BY round(extract('epoch' from timestamp) / 300), name
MySQL
SELECT timestamp, -- not sure about that name, count(b.name) FROM time a, id WHERE … GROUP BY UNIX_TIMESTAMP(timestamp) DIV 300, name
źródło
Natknąłem się na ten sam problem.
Zauważyłem, że łatwo jest grupować według dowolnych minutowych interwałów, po prostu dzieląc epokę przez minuty w ilości sekund, a następnie albo zaokrąglając, albo używając podłogi, aby uzyskać przejechanie pozostałej części. Więc jeśli chcesz uzyskać interwał za 5 minut , użyjesz 300 sekund .
SELECT COUNT(*) cnt, to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300) AT TIME ZONE 'UTC' as interval_alias FROM TABLE_NAME GROUP BY interval_alias
interval_alias cnt ------------------- ---- 2010-11-16 10:30:00 2 2010-11-16 10:35:00 10 2010-11-16 10:45:00 8 2010-11-16 10:55:00 11
To zwróci dane poprawnie pogrupowane według wybranych minut; jednak nie zwróci interwałów, które nie zawierają żadnych danych. Aby uzyskać te puste interwały, możemy użyć funkcji gene_series .
SELECT generate_series(MIN(date_trunc('hour',timestamp_column)), max(date_trunc('minute',timestamp_column)),'5m') as interval_alias FROM TABLE_NAME
Wynik:
interval_alias ------------------- 2010-11-16 10:30:00 2010-11-16 10:35:00 2010-11-16 10:40:00 2010-11-16 10:45:00 2010-11-16 10:50:00 2010-11-16 10:55:00
Teraz, aby otrzymać wynik z interwałem z zerową liczbą wystąpień, po prostu łączymy zewnętrzne zestawy wyników .
SELECT series.minute as interval, coalesce(cnt.amnt,0) as count from ( SELECT count(*) amnt, to_timestamp(floor((extract('epoch' from timestamp_column) / 300 )) * 300) AT TIME ZONE 'UTC' as interval_alias from TABLE_NAME group by interval_alias ) cnt RIGHT JOIN ( SELECT generate_series(min(date_trunc('hour',timestamp_column)), max(date_trunc('minute',timestamp_column)),'5m') as minute from TABLE_NAME ) series on series.minute = cnt.interval_alias
Wynik końcowy będzie obejmował serie ze wszystkimi pięciominutowymi interwałami, nawet te, które nie mają wartości.
interval count ------------------- ---- 2010-11-16 10:30:00 2 2010-11-16 10:35:00 10 2010-11-16 10:40:00 0 2010-11-16 10:45:00 8 2010-11-16 10:50:00 0 2010-11-16 10:55:00 11
Interwał można łatwo zmienić, dostosowując ostatni parametr generowania_serii. W naszym przypadku używamy „5m”, ale może to być dowolny interwał .
źródło
Powinieneś raczej używać
GROUP BY UNIX_TIMESTAMP(time_stamp) DIV 300
zamiast round (../ 300), ponieważ zauważyłem, że niektóre rekordy są zliczane w dwa zgrupowane zestawy wyników.źródło
DIV
w MySQL jestfloor()
podział typu float, który jest bezpieczny dziękiBIGINT
s.W przypadku postgres okazało się, że łatwiejsze i dokładniejsze jest używanie
date_trunc
funkcja, na przykład:
select name, sum(count), date_trunc('minute',timestamp) as timestamp FROM table WHERE xxx GROUP BY name,date_trunc('minute',timestamp) ORDER BY timestamp
Możesz podać różne rozdzielczości, takie jak „minuta”, „godzina”, „dzień” itp. Do date_trunc.
źródło
5
tutaj interwał 5 minut?Zapytanie będzie wyglądać mniej więcej tak:
SELECT DATE_FORMAT( MIN(timestamp), '%d/%m/%Y %H:%i:00' ) AS tmstamp, name, COUNT(id) AS cnt FROM table GROUP BY ROUND(UNIX_TIMESTAMP(timestamp) / 300), name
źródło
Prawdopodobnie będziesz musiał podzielić swój znacznik czasu na ymd: HM i użyć DIV 5, aby podzielić minuty na 5-minutowe pojemniki - coś w rodzaju
select year(a.timestamp), month(a.timestamp), hour(a.timestamp), minute(a.timestamp) DIV 5, name, count(b.name) FROM time a, id b WHERE a.user = b.user AND a.id = b.id AND b.name = 'John' AND a.timestamp BETWEEN '2010-11-16 10:30:00' AND '2010-11-16 11:00:00' GROUP BY year(a.timestamp), month(a.timestamp), hour(a.timestamp), minute(a.timestamp) DIV 12
... a następnie wyświetl wynik w kodzie klienta, aby wyglądał tak, jak lubisz. Lub możesz zbudować cały ciąg daty za pomocą operatora concat sql zamiast pobierania oddzielnych kolumn, jeśli chcesz.
select concat(year(a.timestamp), "-", month(a.timestamp), "-" ,day(a.timestamp), " " , lpad(hour(a.timestamp),2,'0'), ":", lpad((minute(a.timestamp) DIV 5) * 5, 2, '0'))
... a potem pogrupuj to
źródło
Nie jestem pewien, czy nadal go potrzebujesz.
SELECT FROM_UNIXTIME(FLOOR((UNIX_TIMESTAMP(timestamp))/300)*300) AS t,timestamp,count(1) as c from users GROUP BY t ORDER BY t;
źródło
A co z tym:
select from_unixtime(unix_timestamp(timestamp) - unix_timestamp(timestamp) mod 300) as ts, sum(value) from group_interval group by ts order by ts ;
źródło
Dowiedziałem się, że w przypadku MySQL prawdopodobnie poprawne zapytanie jest następujące:
SELECT SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) AS ts_CEILING, SUM(value) FROM group_interval GROUP BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) ORDER BY SUBSTRING( FROM_UNIXTIME( CEILING( timestamp /300 ) *300, '%Y-%m-%d %H:%i:%S' ) , 1, 19 ) DESC
Powiedz mi co myślisz.
źródło
select CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2)) AS '5MINDATE' ,count(something) from TABLE group by CONCAT(CAST(CREATEDATE AS DATE),' ',datepart(hour,createdate),':',ROUNd(CAST((CAST((CAST(DATEPART(MINUTE,CREATEDATE) AS DECIMAL (18,4)))/5 AS INT)) AS DECIMAL (18,4))/12*60,2))
źródło
Pomoże to dokładnie w tym, czego chcesz
wymień dt - twoją datę i godzinę c - wywołanie pola astro_transit1 - twoja tabela 300 odwołaj się 5 minut, więc dodaj 300 za każdym razem, aby zwiększyć odstęp czasowy
SELECT FROM_UNIXTIME( 300 * ROUND( UNIX_TIMESTAMP( r.dt ) /300 ) ) AS 5datetime, ( SELECT r.c FROM astro_transit1 ra WHERE ra.dt = r.dt ORDER BY ra.dt DESC LIMIT 1 ) AS first_val FROM astro_transit1 r GROUP BY UNIX_TIMESTAMP( r.dt ) DIV 300 LIMIT 0 , 30
źródło