2015-04-14 1 views
0

J'ai besoin d'aide pour écrire une requête MySQL.Groupe mysql par où delta entre les enregistrements X

J'ai une table pleine de journaux où l'une des colonnes est un horodatage unix. Je veux grouper (GROUP BY) ces enregistrements de sorte que les événements qui ont été effectués à courte distance (c'est-à-dire 5 secondes) entre chacun d'entre eux appartiennent à un groupe.

Par exemple:

Tableau:

timestamp 
---------- 
1429016966 
1429016964 
1429016963 
1429016960 
1429016958 
1429016957 
1429016950 
1429016949 
1429016943 
1429016941 
1429016940 
1429016938 

Devenir aux groupes comme ça:

GROUP_CONCAT(timestamp)           | COUNT(*) 
----------------------------------------------------------------------------- 
1429016966,1429016964,1429016963,1429016960,1429016958,1429016957 | 6 
1429016950,1429016949            | 2       
1429016943,1429016941,1429016940,1429016938      | 4 

Bien sûr, je peux travailler avec le tableau de données après en php, mais je pense que mysql le ferait plus vite.

+2

débordement de la pile est pas un service d'écriture de code. Qu'avez-vous essayé jusqu'à présent? – NathanOliver

+0

Je vais essayer de résoudre ce problème, mais j'ai donné une réponse similaire [ici] (http://stackoverflow.com/questions/28769211/display-dynamic-ranges-from-a-database-table-and-count- the-rows-within-each-rang/28769750 # 28769750) qui pourrait vous être utile. – AdamMc331

+0

Je sais que ce n'est pas. J'ai déjà cherché pendant quelques heures, mais le meilleur que j'ai trouvé est l'intervalle par groupe, c'est-à-dire 10 min, 1 heure etc. où l'horodatage est divisé par 600, 3600. – Chris

Répondre

0

j'ai commencé en utilisant une variable pour obtenir la position de chaque rangée, où 1 est la plus haute colonne de temps et se terminant avec le plus bas, comme ceci:

SET @a := 0; 

SELECT timeCol, @a := @a + 1 AS position 
FROM myTable 
ORDER BY timeCol DESC; 

Pour simplifier, nous appellerons cette positionsTable si que le reste de la requête sera plus lisible. Une fois que j'ai créé cette table, j'ai utilisé une variable 'time_group' qui vérifiait si une rangée précédente était dans les 5 dernières secondes. Si c'était le cas, nous gardons le même time_group. Il semble laid, et ressemble un peu laid, mais il est comme ça:

SELECT m.timeCol, m.position, 
    CASE WHEN (SELECT p.timeCol FROM positionsTable p WHERE p.position = m.position - 1) <= m.timeCol + 5 
    THEN @time_group 
    ELSE @time_group := @time_group + 1 END AS timeGroup 
FROM positionsTable m; 

Et puis en fin de compte, en utilisant cela comme un sous-requête, vous pouvez les regrouper:

SELECT GROUP_CONCAT(timeCol), COUNT(*) 
FROM(
    SELECT m.timeCol, m.position, 
    CASE WHEN (SELECT p.timeCol FROM positionsTable p WHERE p.position = m.position - 1) <= m.timeCol + 5 
    THEN @time_group 
    ELSE @time_group := @time_group + 1 END AS timeGroup 
    FROM positionsTable m) tmp 
GROUP BY timeGroup; 

Voici un exemple SQL Fiddle.

0

http://sqlfiddle.com/#!9/37d88/20

SELECT GROUP_CONCAT(t1.t) as `time`, 
    COUNT(*) 
    FROM (SELECT * 
     FROM table1 
     ORDER BY t) as t1 
GROUP BY CASE WHEN (@start+5)>=t THEN @start 
    ELSE @start:=t END