Question

Bonne journée à tous.

J'ai cet environnement: sur une base de données MySQL, chaque fois qu'un utilisateur se connecte sur un site, il est créé une nouvelle ligne, avec son nom et le moment où il se connecte. Étant donné que le système est exclusif mutuel, il n'y aura qu'un utilisateur à un moment donné, et si un nouvel utilisateur arrive, celui enregistré est déconnecté.

Maintenant, ils m'ont demandé de calculer le temps total de tous les utilisateurs sur le système, donc en gros, je dois résumer tous les différences de temps par rapport à une connexion et à son prochain.

user  |       timestamp     |
------------------------------
alpha | 2013-01-19 03:14:07
beta  | 2013-01-20 11:24:04
alpha | 2013-01-21 02:11:37
alpha | 2013-01-21 03:10:31    <---- a user could login twice, it is normal
gamma | 2013-01-21 11:24:04
beta  | 2013-01-21 11:25:00

Je voudrais vous demander votre avis, car il y a beaucoup de connexions, qui est le meilleur moyen de calculer le temps total enregistré d'un utilisateur? Dans cet exemple, "Gamma" aura un temps de connexion de 56 secondes, et la dernière connexion de la version bêta pourrait être ignorée, car elle sera en ligne au moment de l'exécution de ce chèque. Donc, "Beta" n'aura qu'une seule entrée.

Existe-t-il un moyen de le calculer via la requête? Ou vaut mieux ajouter une colonne "temps en ligne" et laisser le sistem calculer chaque fois qu'une déconnexion utilisateur a passé du temps en ligne?

Était-ce utile?

La solution

Cela nécessite une auto-jointure si vous le faites dans MySQL. C'est une douleur dans le cou de faire une auto-jointure car MySQL n'a pas de fonction Rownum intégrée. Mais c'est toujours faisable.

Tout d'abord, nous devons créer une sous-requête pour créer une table virtuelle simulant SELECT rownum, user, timestamp FROM login que nous pouvons faire comme ça. http://sqlfiddle.com/#!2/bf6ef/2/0

SELECT @a:=@a+1 AS rownum, user, timestamp
    FROM (
        SELECT user, timestamp
          FROM login
         ORDER BY timestamp
    ) C,
    (SELECT @a:=0) s

Ensuite, nous devons faire une auto-jointure de cette table virtuelle à une copie de lui-même. Ce que nous voulons dans cet ensemble de résultats est une liste de toutes les paires de lignes consécutives dans le tableau. Cette requête est une boule de cheveux - elle met le structuré dans Langage de requêtes structurées. Mais ça marche. C'est ici: http://sqlfiddle.com/#!2/bf6ef/4/0

SELECT first.user AS fuser, 
       first.timestamp AS ftimestamp,
       second.user AS suser,
       second.timestamp as stimestamp,
       TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin

  FROM (
       SELECT @a:=@a+1 AS rownum, user, timestamp
         FROM (
             SELECT user, timestamp
               FROM login
           ORDER BY timestamp
              ) C,
          (SELECT @a:=0) s
        ) AS first
  JOIN (
       SELECT @b:=@b+1 AS rownum, user, timestamp
         FROM (
             SELECT user, timestamp
               FROM login
           ORDER BY timestamp
              ) C,
          (SELECT @b:=0) s
        ) AS second ON first.rownum+1 = second.rownum

L'astuce pour comparer les lignes consécutives est le

SELECT (virtual_table) AS first
  JOIN (virtual_table) AS second ON first.rownum+1 = second.rownum

modèle de requête. Le Rownum + 1 = Rownum Thing rassemble les lignes avec des numéros de ligne consécutifs ensemble.

Ensuite, nous devons résumer le résultat de cette requête pour obtenir le temps total connecté pour chaque utilisateur. Cela fonctionnera comme ceci:

  SELECT user, SUM(timeloggedin) AS timeloggedin
    FROM (
          /* the self-joined query */
         ) AS selfjoin
   GROUP BY user
   ORDER BY user

Cela ressemble à ceci: http://sqlfiddle.com/#!2/bf6ef/5/0

C'est toute la requête assemblée.

SELECT user, SUM(timeloggedin) AS timeloggedin
  FROM (
      SELECT first.user AS user, 
             TIMESTAMPDIFF(SECOND, first.timestamp, second.timestamp) AS timeloggedin
        FROM (
             SELECT @a:=@a+1 AS rownum, user, timestamp
         FROM (
                   SELECT user, timestamp
                     FROM login
                 ORDER BY timestamp
                    ) C,
                (SELECT @a:=0) s
              ) AS first
        JOIN (
             SELECT @b:=@b+1 AS rownum, user, timestamp
               FROM (
                   SELECT user, timestamp
                     FROM login
                 ORDER BY timestamp
                    ) C,
                (SELECT @b:=0) s
              ) AS second ON first.rownum+1 = second.rownum
         ) AS selfjoin
   GROUP BY user
   ORDER BY user

Ce n'est pas vraiment intuitif pour quelqu'un habitué à la pensée procédurale, algorithmique. Mais c'est ainsi que vous faites ce type de comparaison consécutive dans SQL.

Autres conseils

Essayez avec cela ... moins ou plus est la solution de votre problème ...

    CREATE TABLE `matteo` (
      `user` varchar(20) DEFAULT NULL,
      `timestamp` int(11) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 7);
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 9);
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 17);
    INSERT INTO matteo(user, `timestamp`) VALUES ('alpha', 27);
    INSERT INTO matteo(user, `timestamp`) VALUES ('gamma', 77);
    INSERT INTO matteo(user, `timestamp`) VALUES ('beta', 97);

    select a.*,b.*,b.`timestamp`-a.`timestamp` as delta
    from
    (SELECT @rownum := @rownum + 1 AS id,t.*
          FROM matteo t,(SELECT @rownum := 0) r) a
    join
    (SELECT @rownum2 := @rownum2 + 1 AS id,t.*
          FROM matteo t,(SELECT @rownum2 := 0) r) b 
    where a.id=b.id-1

:-) Voyez-vous lundi !!!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top