MySQL группа по интервалам в диапазоне дат - PullRequest
6 голосов
/ 22 октября 2009

Я собираюсь отобразить данные сетевого потока, хранящиеся в базе данных MySQL, и мне нужен эффективный способ получить соответствующие точки данных. Эти записи хранятся с датой в виде int в течение нескольких секунд с начала эпохи. Я хотел бы иметь возможность что-то вроде:

Select SUM(bytes) from table where stime > x and stime < Y  
group by (10 second intervals)

Есть ли что-нибудь, чтобы сделать это? или это будет быстрее обрабатывать это локально в Python? даже для таблицы строк 500К?

EDIT Моя ошибка, время хранится в виде двойного знака без знака вместо INT. В настоящее время я использую GROUP BY (FLOOR(stime / I)), где я - желаемый интервал.

Ответы [ 6 ]

4 голосов
/ 22 октября 2009

Вы можете сделать это, используя целочисленное деление. Не уверен в производительности.

Позвольте мне быть вашим желаемым интервалом в секундах.

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
2 голосов
/ 22 октября 2009

Вы пробовали следующее? Просто разделите столбец tyiem на 10 и округлите результат вниз.

SELECT    SUM(bytes) 
FROM      table 
WHERE     stime > x 
AND       stime < Y
GROUP BY  ROUND(stime/10, -1)

Я не знаю, работает ли функция ROUND (), и группировка с вызовами функций работает в MySQL, хотя выше приведен T-SQL.

1 голос
/ 09 июня 2011
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
1 голос
/ 23 февраля 2010

FLOOR в группе иногда дает сбой. иногда он группирует разные времена как одно значение, например, когда вы делите значение на 3, но он не делает то же самое, когда вы делите на 4, хотя разница между этими двумя значениями намного больше, чем 3 или 4, которые следует сгруппировать как две разные группы. Лучше бросить его без знака после пола, который работает как:

CAST(FLOOR(UNIX_TIMESTAMP(time_field)/I) AS UNSIGNED INT)

Проблема:

Иногда GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/3) дает меньше групп по сравнению с GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/4), что математически не должно быть возможным.

0 голосов
/ 23 февраля 2010

Я сделал это несколько раз назад, поэтому я создал некоторую функцию (с сервером SQL, но я предполагаю, что это почти то же самое):

Сначала я создал скалярную функцию, которая возвращает мне идентификатор даты в зависимости от интервала и части даты (минута, час, день, месяц, год):

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

Затем я создал табличную функцию, которая возвращает мне все идентификаторы между диапазонами дат:

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

Итак, если я хочу посчитать всех пользователей, добавленных за каждый интервал в 33 минуты:

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, 'minute', 33) ORDER BY timeTable.StartDate

:)

0 голосов
/ 23 октября 2009

Я использовал предложения обоих ответов и коллеги. Конечный результат выглядит следующим образом:

Select FROM_UNIXTIME(stime), bytes 
from argusTable_2009_10_22 
where stime > (UNIX_TIMESTAMP()-600)
group by floor(stime /10)

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

Chance

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...