Comment combiner deux lignes et calculer la différence de temps entre deux valeurs d'horodatage dans MySQL?
J'ai une situation qui, je suis sûr que c'est assez commun et il est vraiment à me tracasser que je ne peux pas comprendre comment le faire ou quoi chercher pour trouver un exemple pertinent/solution. Je suis relativement nouveau à MySQL (qui ont été à l'aide de MYSQL et PostgreSQL) et chaque approche, je pense, bloqué par certaines caractéristiques défaut dans MySQL.
J'ai une "du journal" le tableau qui énumère simplement beaucoup de différents événements avec leur date et heure (stockés en tant que type datetime). Il y a beaucoup de données et les colonnes du tableau ne sont pas pertinentes à ce problème, donc disons que nous avons un simple tableau comme ceci:
CREATE TABLE log (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(16),
ts DATETIME NOT NULL,
eventtype VARCHAR(25),
PRIMARY KEY (id)
)
Disons que certaines lignes ont un eventtype = "start" et d'autres ont un eventtype = 'stop'. Ce que je veux faire, c'est en quelque sorte à chaque couple "startrow" à chaque "stoprow" et de trouver la différence de temps entre les deux (et puis additionner les durées pour chaque nom, mais ce n'est pas où se trouve le problème). Chaque "démarrer" de l'événement doit correspondre un "stop" de l'événement se produisant à un moment plus tard, alors que le "début" de l'événement, mais à cause de problèmes/bugs/s'est écrasé avec le collecteur de données, il est possible que certains sont manquants. Dans ce cas, je voudrais d'ignorer l'événement sans un "partenaire". Cela signifie que les données:
foo, 2010-06-10 19:45, start
foo, 2010-06-10 19:47, start
foo, 2010-06-10 20:13, stop
..Je voudrais juste ignorer le 19:45 de début de l'événement et de ne pas simplement obtenir deux lignes de résultats à la fois à l'aide de l'20:13 arrêt événement comme le temps à l'arrêt.
J'ai essayé de joindre la table avec elle-même de différentes manières, mais la clé de problèmes pour moi semble être de trouver un moyen d'identifier correctement le correspondant "stop" événement "start" de l'événement pour le "nom". Le problème est exactement le même que vous auriez si vous aviez de la table avec les employés d'estampage et de travail et je voulais savoir combien ils étaient réellement au travail. Je suis sûre qu'il doit être bien connue des solutions, mais je n'arrive pas à les trouver...
source d'informationauteur Nadar
Vous devez vous connecter pour publier un commentaire.
Je crois que ça pourrait être un moyen plus simple pour atteindre votre objectif:
Il doit courir beaucoup plus vite, car elle élimine une sous-requête.
Si vous n'avez pas l'esprit de la création d'une table temporaire*, alors je pense que la suite devrait bien fonctionner. Je l'ai testé avec de 120 000 dossiers, et l'ensemble du processus se termine en moins de 6 secondes. Avec de 1 048 576 dossiers terminé en un peu moins de 66 secondes - et c'est sur un vieux Pentium III avec 128 mo de RAM:
*En MySQL 5.0 (et peut-être d'autres versions) la table temporaire ne peut pas être un vrai MySQL table temporaire, comme vous ne peut pas se référer à une table TEMPORAIRE plus d'une fois dans la même requête. Voir ici:
http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html
Au lieu de cela, il suffit de déposer/créer un tableau normal, comme suit:
Cette table est utilisée pour stocker un classement et liste numérotée des lignes de la requête de sélection suivante:
Ci-dessus requête SELECT trie les lignes par le nom et l'id (vous pouvez utiliser le timestamp au lieu de l'id, si tant est que le début des événements apparaissent avant l'arrêt des événements). Chaque ligne est numérotée. En faisant cela, les paires d'événements sont toujours à côté de l'autre, et le numéro de ligne du début de l'événement est toujours un de moins que la ligne id de l'événement d'arrêt.
Maintenant, sélectionnez les paires correspondantes de la liste:
Une fois que vous avez terminé, il est probablement une bonne idée de supprimer la table temporaire:
Mise à JOUR
Vous pouvez essayer de l'idée suivante, ce qui élimine le temp des tables et des jointures complètement en utilisant des variables pour stocker des valeurs de la rangée précédente. Il trie les lignes par le nom puis le temps de timbre, qui regroupe toutes les valeurs avec le même nom, et met chaque groupe dans l'ordre du temps. Je pense que cela devrait s'assurer que tous les correspondants start/stop événements sont à côté les uns des autres.
Je ne sais pas comment il va comparer à Ivar Bonsaksen de la méthode, mais il fonctionne assez rapide sur ma boîte.
Voici comment j'ai créé les données de test:
Pouvez-vous changer le collecteur de données? Si oui, ajouter un group_id champ (avec un index) dans la table du journal et écrire l'id de l'événement (le même id de début et de fin dans le group_id).
Ensuite, vous pouvez faire
De l'essayer.
Comment à ce sujet:
Cela permettra de trouver chaque paire de lignes (alias
start_log
etend_log
) avec aucun des événements entre les deux, où le premier est toujours un début et le dernier est toujours un arrêt. Puisque nous interdire l'intermédiaire d'événements, un début qui n'est pas immédiatement suivi d'un arrêt sera naturellement exclus.J'ai eu de travail en combinant vos deux solutions, mais la requête n'est pas très efficace, et je n'aurais pensé qu'il y aurait une façon plus intelligente d'omettre ces indésirables lignes.
Ce que j'ai maintenant est:
Limitée à un "nom", la requête va d'environ 0,5 secondes environ 14 secondes quand j'inclus le
WHERE NOT EXISTS
clause... La table va devenir très grand et je suis inquiet au sujet de combien d'heures cela va prendre pour tous les noms à la fin. Je suis actuellement seulement avoir des données pour le mois de juin 2010 dans le tableau (10 jours) et c'est maintenant à 109888 lignes.