2010-12-13 9 views
2

Je travaille sur un jeu dont le suivi est la durée pendant laquelle vous êtes connecté. Il enregistre une heure d'enregistrement dans la base de données, ainsi qu'une date de départ.Soustraction de date SQL avancée

C'est un jeu, quelque chose comme capturer le drapeau, seulement ce que je ne veux pas qu'il fasse est de compter le temps entre 18h00 (18h00) et 09h00 (9h00) avec le score. Cela vaut pour tous les jours, et pas seulement une fois.

Le score est af inché en secondes. Il est facile de dire que c'est la différence entre le check-in et le check-out (moins le temps entre 18h00 et 09h00, pour tous les jours).

Est-ce que quelqu'un est un expert dans les calculs avancés de date SQL et peut m'aider? S'il vous plaît!

Ceci est ma requête de base, sans la soustraction du temps:

SELECT 
SUM(TIMESTAMPDIFF(SECOND,sessions.checkin,IFNULL(sessions.checkout,NOW()))) 
AS score 
FROM `sessions` 
GROUP BY `user_id` 
+0

Est-ce que cela doit être complètement dans MySQL ou peut-il être fait dans votre langage de programmation? Cela ressemble à une requête très compliquée. – Danosaure

+0

il peut également être fait en php, si vous préférez .. Serait-il fonctionner de la façon suivante: calculer la différence entre 18h00 et 09h00 et multiplier avec les jours qui ont passé? – sparkle

Répondre

1

Il ne sera pas assez (vous pouvez ajouter functions pour une meilleure lisibilité de vos requêtes si vous allez faire beaucoup)

En supposant que vous n'avez pas les connexions répartis sur plusieurs jours, vous pouvez effectuer les opérations suivantes

SELECT 
     user_id, 
     SUM(
      TIMESTAMPDIFF(SECOND, 
      CASE 
       WHEN sessions.checkin < timestamp(date(sessions.checkin), maketime(9,0,0)) 
        THEN timestamp(date(sessions.checkin), maketime(9,0,0)) 
       WHEN sessions.checkin > timestamp(date(sessions.checkin), maketime(18,0,0)) 
        THEN timestamp(date(sessions.checkin)+1, maketime(9,0,0)) 
       ELSE 
        sessions.checkin 
      END, 
      CASE 
       WHEN IFNULL(sessions.checkout, now()) > timestamp(date(IFNULL(sessions.checkout, now())), maketime(18,0,0)) 
        THEN timestamp(date(IFNULL(sessions.checkout, now())), maketime(18,0,0)) 
       WHEN IFNULL(sessions.checkout, now()) < timestamp(date(IFNULL(sessions.checkout, now())), maketime(9,0,0)) 
        THEN timestamp(date(IFNULL(sessions.checkout, now()))-1, maketime(18,0,0)) 
       ELSE 
        IFNULL(sessions.checkout, now()) 
      END)) AS score 
    FROM `sessions` 
    GROUP BY `user_id` 

Il ne fonctionne pas si les connexions que plusieurs jours ou enjambent pour être p recise la requête peut fonctionner avec des connexions qui s'étendent sur plusieurs jours tels que checkin à 18h05 le premier jour et checkout à 8h55 le 3ème jour, mais dès qu'il s'étend sur un temps comptable sur plusieurs jours, la caluclation n'est pas terminée - pour chaque enregistrement qui s'étend sur des durées comptables sur plusieurs jours, vous devez soustraire le nombre de secondes non dénombrables du résultat. Faites-moi savoir si vous avez besoin d'aide pour cela. La requête ci-dessus devrait fonctionner relativement bon marché - étant donné que vous l'exécutez sur toute la table de toute façon, donc il va faire un scan de table, le fait qu'il y ait beaucoup de calculs répétés et que ça ressemble énorme ne devrait pas importer autant. Ces calculs se produisent en mémoire sans E/S supplémentaires et cela devrait se produire de quelques ordres de grandeur plus rapidement que les E/S disque (comparez avec le temps d'exécution de votre requête d'origine et faites-nous savoir si les performances sont dégradées).

+0

J'ai fait quelques modifications au script que vous me fournissez et ça marche! Merci mec. Je dois dire que c'était juste une sous-requête d'une requête plus grande. maintenant c'est énorme. LOL. mais ce n'est pas un problème! – sparkle