2009-10-22 6 views
6

Je vais représenter graphiquement des données Netflow stockées dans une base de données MySQL, et j'ai besoin d'un moyen efficace d'obtenir les points de données pertinents. Ces enregistrements sont stockés avec la date en tant qu'int pour les secondes depuis l'époque. Je voudrais être en mesure de quelque chose comme:Groupe MySQL par intervalles dans une plage de dates

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

Y at-il de toute façon à faire cela? ou, serait-il plus rapide de le gérer localement en python? même pour une table en rangée 500K?

EDIT My Mistake, l'heure est stockée comme un double non signé au lieu d'un INT. J'utilise actuellement GROUP BY (FLOOR(stime/I)) où I est l'intervalle désiré.

Répondre

0

J'ai utilisé des suggestions des réponses et d'un collègue. Le résultat final est le suivant:

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

J'ai également essayé la solution arrondie, mais les résultats étaient incohérents.

Chance

2

Avez-vous essayé ce qui suit? Il suffit de diviser la colonne tyiem par 10 et arrondir le résultat à la baisse.

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

Je ne sais pas wether la fonction ROND() et le regroupement des appels de fonction des travaux dans MySQL cependant, ce qui précède est T-SQL.

+0

ronde me donne des intervalles très variables, sur une période de dix minutes, je reçois des intervalles petit comme 7secs, et certains aussi grand que 1 min ... – Chance

4

Vous pouvez faire cela en utilisant la division entière. Pas sûr de la performance.

Laissez-moi être votre intervalle désiré en secondes.

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 
0

FLOOR dans le groupe par échoue parfois. il regroupe parfois des valeurs différentes en une seule valeur, par exemple lorsque vous divisez la valeur par 3, mais elle ne fait pas la même chose lorsque vous divisez avec 4, bien que la différence entre ces deux valeurs soit nettement supérieure à 3 ou 4 deux groupes différents. Mieux jeter unsigned après étage, qui fonctionne comme:

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

Le problème:

Parfois GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/3) donne des groupes moins par rapport à GROUP BY FLOOR(UNIX_TIMESTAMP(time_field)/4) qui est mathématiquement ne devrait pas être possible.

+1

C'est mathématiquement très bien possible. Supposons que les valeurs sont "3" et "4", puis divisées par 3 toutes les deux donnent 1, tandis que divisées par 4 elles donnent 0 et 1. Donc le regroupement par/4 donnera plus de groupes dans ce cas. – sth

0

Je l'ai fait il y a peu de temps, donc je créé une fonction (avec le serveur SQL, mais je suppose qu'il est à peu près le même):

D'abord, je créé une fonction scalaire qui me renvoient l'identifiant d'une date en fonction sur un intervalle et une partie date (minute, heure, jour, papillon de nuit, année):

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 

Ensuite, je crée une fonction de table qui me retourne tous les id betweend une plage de dates:

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 

Donc, si je veux compter tous les utilisateurs ajoutés pour chaque intervalle de 33 minutes:

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 

GROUPE BY dbo.getIDDate (user.creation_date, 'minute', 33) ORDER BY timeTable.StartDate

:)

1
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 
Questions connexes