2009-11-03 4 views
1

J'ai un fichier journal dans SqlServer qui stocke l'heure à laquelle une application a démarré, l'heure à laquelle l'application est prête (chargement terminé), et le temps qu'il est sorti. Chacun d'eux se présente comme une entrée séparée. Le format (et les données de l'échantillon) comme suit:Méthode de détermination de la différence de temps entre un "groupe" d'enregistrements via SQL

Date/Time     User Type Application Message 
2009-11-03 12:26:12.403 uname1 Info app1   Started  
2009-11-03 12:26:22.403 uname1 Info app1   Loaded 
2009-11-03 12:27:15.403 uname2 Info app1   Started  
2009-11-03 12:27:16.401 uname1 Info app1   Exited 
2009-11-03 12:27:18.403 uname2 Info app1   Loaded 
2009-11-03 12:29:12.403 uname2 Info app1   Exited 

Je voudrais savoir, par application et par utilisateur, la quantité de temps qu'il a fallu pour l'application pour obtenir un prêt et que la quantité de l'heure de fonctionnement de l'application. Ce serait un morceau de gâteau si chaque date/heure était dans le même enregistrement, et il serait également facile (quoique fastidieux) de simplement charger chaque enregistrement comme un curseur et passer au crible les données, mais je pensais qu'il doit y avoir un moyen de le faire "correctement" d'une manière théorique.

Donc, je le répète, la sortie suivante (à partir des données de l'échantillon ci-dessus) sera prévu (les chiffres sont en quelques secondes, arrondi):

User Application Ready Uptime 
uname1 app1   10  64 
uname2 app1   3  117 

Toutes les suggestions?

EDIT: La bonne nouvelle est que l'application ne peut être démarrée qu'une seule fois. MAIS, le journal ne pas prendre en compte si l'application s'est écrasé (bien que je suppose que je pourrais rechercher "sorti" et "écrasé" comme conditions finales).

Répondre

2

Que diriez-vous

Select S.user, S.Application, 
     S.DateTime Started, L.DateTime Loaded, X.DateTime Exited, 
     L.DateTime - S.DateTime LoadTime, 
     X.DateTime - L.DateTime RunTime 
    From LogFile S 
     Full Join LogFile L 
      On S.Message = 'Started' 
      And L.Message = 'Loaded' 
      And L.User = S.user 
      And L.Application = S.Application 
      And L.DateTime = (Select Min(DateTime) 
           From LogFile 
           Where Message = 'Loaded' 
           And application = S.Application 
           And user = S.user 
           And DateTime > S.DateTime) 
     Full Join LogFile X 
      On L.Message = 'Loaded' 
      And X.Message = 'Exited' 
      And X.User = L.user 
      And X.Application = L.Application 
      And X.DateTime = (Select Min(DateTime) 
           From LogFile 
           Where Message = 'Exited' 
            And application = L.Application 
            And user = L.user 
            And DateTime > L.DateTime) 

appliquer ensuite les fonctions d'agrégation à cela pour ce que vous voulez:

Select user, Application, 
    Sum(LoadTime) TotLoadTime, 
    Sum(RunTime) TotalRunTime 
From 
     (Select S.user, S.Application, 
     S.DateTime Started, L.DateTime Loaded, X.DateTime Exited, 
     L.DateTime - S.DateTime LoadTime, 
     X.DateTime - L.DateTime RunTime 
     From LogFile S 
      Full Join LogFile L 
      On S.Message = 'Started' 
       And X.Message = 'Loaded' 
       And L.User = S.user 
       And L.Application = S.Application 
       And L.DateTime = 
         (Select Min(DateTime) 
         From LogFile 
         Where Message = 'Loaded' 
          And application = S.Application 
          And user = S.user 
          And DateTime > S.DateTime) 
     Full Join LogFile X 
      On L.Message = 'Loaded' 
       And X.Message = 'Exited' 
       And X.User = L.user 
       And X.Application = L.Application 
       And X.DateTime = 
         (Select Min(DateTime) 
         From LogFile 
         Where Message = 'Exited' 
          And application = L.Application 
          And user = L.user 
          And DateTime > L.DateTime)) Z 
Group By user, Application 
+0

Aussi hideux que cela soit, cela fonctionne vraiment. Et cela n'a pris que 2 secondes de temps serveur pour l'attraper. Merci. –

+0

Merci beaucoup pour cela. J'essayais de trouver de nombreuses méthodes pour résoudre ce problème et j'étais sur le point de lever la main et d'écrire un programme pour le faire. C'est beaucoup plus facile et plus rapide. –

+0

wellll ... merci beaucoup pour le commentaire hideux (je plaisante!) Vous êtes les bienvenus! –

3

Je préférerais ne pas me joindre à la même table plusieurs fois, surtout si la table devient énorme. C'est en quelque sorte une approche en deux étapes. La première passe trie les temps dans les bons endroits, et le second passage les replie par l'utilisateur et de l'application:

SELECT 
    User, 
    Application, 
    MAX(StartTime) StartTime, 
    MAX(ReadyTime) ReadyTime, 
    MAX(ExitTime) ExitTime, 
FROM (
    SELECT 
    User, 
    Application, 
    CASE (
     WHEN Message = 'Started' THEN Date/Time 
     ELSE NULL 
    ) StartTime, 
    CASE (
     WHEN Message = 'Loaded' THEN Date/Time 
     ELSE NULL 
    ) ReadyTime, 
    CASE (
     WHEN Message = 'Exited' THEN Date/Time 
     ELSE NULL 
    ) ExitTime 
    FROM Log 
) Log 
GROUP BY 
    User, 
    Application 

Et à partir de là il est trivial de calculer tout ce que vous voulez sur ces différents moments.

Ce n'est pas vraiment une «théorie des ensembles», mais le regroupement et l'agrégation ne le sont jamais. Comme la solution d'Eric, il ne gère pas la situation lorsque le même utilisateur a utilisé l'application plusieurs fois. Vous auriez besoin d'une troisième colonne de regroupement (comme "session" ou quelque chose) pour gérer ce scénario.

+0

Malheureusement, cela ne donne que le temps _dernière_ l'utilisateur a commencé et a quitté l'application. J'espérais quelque chose qui donnerait à _each_ start/exit sur une période de temps donnée. Je vais continuer à essayer de travailler avec ça, cependant. –

Questions connexes