grupo MySQL por intervalos em um intervalo de datas
Pergunta
Vou ser graficamente dados NetFlow armazenados em um banco de dados MySQL, e eu preciso de uma maneira eficiente para obter os pontos de dados relevantes. Eles registros são armazenados com a data como um int para segundos desde época. Eu gostaria de ser capaz de algo como:
Select SUM(bytes) from table where stime > x and stime < Y
group by (10 second intervals)
Existe uma maneira de fazer isso? ou, seria mais rápido para lidar com isso localmente em python? mesmo para uma mesa 500K linha?
Editar
Meu erro, o tempo é armazenado como um sem assinatura de casal em vez de uma INT.
Atualmente estou usando GROUP BY (FLOOR(stime / I))
onde I é o intervalo desejado.
Solução 5
Eu costumava sugestões de ambas as respostas e um colega de trabalho. O resultado final é a seguinte:
Select FROM_UNIXTIME(stime), bytes
from argusTable_2009_10_22
where stime > (UNIX_TIMESTAMP()-600)
group by floor(stime /10)
Eu tentei a solução arredondamento bem, mas os resultados foram inconsistentes.
Possibilidade
Outras dicas
Você pode ser capaz de fazer isso usando divisão inteira. Não tenho certeza do desempenho.
Seja I o intervalo desejado em segundos.
SELECT SUM(bytes), ((stime - X) DIV I) as interval
FROM table
WHERE (stime > X) and (stime < Y)
GROUP BY interval
Example, let X = 1500 and I = 10
stime = 1503 -> (1503 - 1500) DIV 10 = 0
stime = 1507 -> (1507 - 1500) DIV 10 = 0
stime = 1514 -> (1514 - 1500) DIV 10 = 1
stime = 1523 -> (1523 - 1500) DIV 10 = 2
Você já tentou o seguinte? Apenas dividir a coluna tyiem por 10 e em volta do baixo resultado.
SELECT SUM(bytes)
FROM table
WHERE stime > x
AND stime < Y
GROUP BY ROUND(stime/10, -1)
Eu não sei wether a função ROUND () e agrupamento com chamadas função funciona no MySQL, porém, o acima é T-SQL.
FLOOR
no grupo por vezes falha. TI vezes, por vezes grupos diferentes como um valor, por exemplo, quando você divide o valor com 3 mas não fazer o mesmo quando você divide com 4, embora a diferença entre estes dois valores é muito maior do que 3 ou 4, que deveria grupo como dois grupos diferentes. Melhor lançá-lo aos não assinado depois de andar que funciona como:
CAST(FLOOR(UNIX_TIMESTAMP(time_field)/I) AS UNSIGNED INT)
O problema:
Às vezes GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/3)
dá menos grupos em comparação com GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/4)
que é matematicamente não deveria ser possível.
SELECT sec_to_time(time_to_sec(datefield)- time_to_sec(datefield)%(10)) as intervals,SUM(bytes)
FROM table
WHERE where stime > x and stime < Y
group by intervals
Eu fiz isso há pouco tempo, então eu criei alguma função (com o SQL Server, mas eu suponho que é quase o mesmo):
Primeiro eu criei uma função escalar que me devolver o ID de uma data de acordo com um intervalo e uma parte da data (minuto, hora, dia, traça, ano):
CREATE FUNCTION [dbo].[GetIDDate]
(
@date datetime,
@part nvarchar(10),
@intervalle int
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
DECLARE @res int
DECLARE @date_base datetime
SET @date_base = convert(datetime,'01/01/1970',103)
set @res = case @part
WHEN 'minute' THEN datediff(minute,@date_base,@date)/@intervalle
WHEN 'hour' THEN datediff(hour,@date_base,@date)/@intervalle
WHEN 'day' THEN datediff(day,@date_base,@date)/@intervalle
WHEN 'month' THEN datediff(month,@date_base,@date)/@intervalle
WHEN 'year' THEN datediff(year,@date_base,@date)/@intervalle
ELSE datediff(minute,@date_base,@date)/@intervalle END
-- Return the result of the function
RETURN @res
END
Em seguida, eu criei uma função de tabela que retorna-me todo o id betweend um intervalo de datas:
CREATE FUNCTION [dbo].[GetTableDate]
(
-- Add the parameters for the function here
@start_date datetime,
@end_date datetime,
@interval int,
@unite varchar(10)
)
RETURNS @res TABLE (StartDate datetime,TxtStartDate nvarchar(50),EndDate datetime,TxtEndDate nvarchar(50),IdDate int)
AS
begin
declare @current_date datetime
declare @end_date_courante datetime
declare @txt_start_date nvarchar(50)
declare @txt_end_date nvarchar(50)
set @current_date = case @unite
WHEN 'minute' THEN dateadd(minute, datediff(minute,0,@start_date),0)
WHEN 'hour' THEN dateadd(hour, datediff(hour,0,@start_date),0)
WHEN 'day' THEN dateadd(day, datediff(day,0,@start_date),0)
WHEN 'month' THEN dateadd(month, datediff(month,0,@start_date),0)
WHEN 'year' THEN dateadd(year, datediff(year,0,dateadd(year,@interval,@start_date)),0)
ELSE dateadd(minute, datediff(minute,0,@start_date),0) END
while @current_date < @end_date
begin
set @end_date_courante =
case @unite
WHEN 'minute' THEN dateadd(minute, datediff(minute,0,dateadd(minute,@interval,@current_date)),0)
WHEN 'hour' THEN dateadd(hour, datediff(hour,0,dateadd(hour,@interval,@current_date)),0)
WHEN 'day' THEN dateadd(day, datediff(day,0,dateadd(day,@interval,@current_date)),0)
WHEN 'month' THEN dateadd(month, datediff(month,0,dateadd(month,@interval,@current_date)),0)
WHEN 'year' THEN dateadd(year, datediff(year,0,dateadd(year,@interval,@current_date)),0)
ELSE dateadd(minute, datediff(minute,0,dateadd(minute,@interval,@current_date)),0) END
SET @txt_start_date = case @unite
WHEN 'minute' THEN CONVERT(VARCHAR(20), @current_date, 100)
WHEN 'hour' THEN CONVERT(VARCHAR(20), @current_date, 100)
WHEN 'day' THEN REPLACE(CONVERT(VARCHAR(11), @current_date, 106), ' ', '-')
WHEN 'month' THEN REPLACE(RIGHT(CONVERT(VARCHAR(11), @current_date, 106), 8), ' ', '-')
WHEN 'year' THEN CONVERT(VARCHAR(20), datepart(year,@current_date))
ELSE CONVERT(VARCHAR(20), @current_date, 100) END
SET @txt_end_date = case @unite
WHEN 'minute' THEN CONVERT(VARCHAR(20), @end_date_courante, 100)
WHEN 'hour' THEN CONVERT(VARCHAR(20), @end_date_courante, 100)
WHEN 'day' THEN REPLACE(CONVERT(VARCHAR(11), @end_date_courante, 106), ' ', '-')
WHEN 'month' THEN REPLACE(RIGHT(CONVERT(VARCHAR(11), @end_date_courante, 106), 8), ' ', '-')
WHEN 'year' THEN CONVERT(VARCHAR(20), datepart(year,@end_date_courante))
ELSE CONVERT(VARCHAR(20), @end_date_courante, 100) END
INSERT INTO @res (
StartDate,
EndDate,
TxtStartDate,
TxtEndDate,
IdDate) values(
@current_date,
@end_date_courante,
@txt_start_date,
@txt_end_date,
dbo.GetIDDate(@current_date,@unite,@interval)
)
set @current_date = @end_date_courante
end
return
end
Então, se eu quero contar tudo que o usuário adicionado para cada intervalo de 33 minutos:
SELECT count(id_user) , timeTable.StartDate
FROM user
INNER JOIn dbo.[GetTableDate]('1970-01-01',datedate(),33,'minute') as timeTable
ON dbo.getIDDate(user.creation_date,'minute',33) = timeTable.IDDate
GROUP BY dbo.getIDDate (user.creation_date, 'minutos', 33) ORDER BY timeTable.StartDate
:)