dongxian5735 2013-11-07 15:43
浏览 75
已采纳

在mysql表上计算经过的时间

Good day all.

I have this environment: on a Mysql db, everytime a user logins on a site, it is created a new row, with his name, and the time when he login. Since the system is mutual exclusive, there will be only a user at a given time, and if a new user arrive, the one logged is logged off.

now they have asked to me to calculate the total time of all users on the system, so basically, i have to sum together all the time differences from a login and its next one.

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

I would like to ask your opinion, since there are a lot of logins, which is the best way to calculate the total logged time of a user? in this example "gamma" will have a login time of 56 seconds, and the last login of beta could be ignored, since it will be online at the time of the execution of this check. so "beta" will have only one entry.

is there a way yo calculate it via query? or is better to add a column "time online" and let the sistem calculate each time a user logout how much time has spent online?

  • 写回答

2条回答 默认 最新

  • dpd7195 2013-11-07 16:27
    关注

    This requires a self-join if you are to do it in MySQL. It's a pain in the neck to do a self-join because MySQL has no built in rownum function. But it's still doable.

    First, we need to create a subquery to create a virtual table simulating SELECT rownum, user, timestamp FROM login which we can do like this. 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
    

    Next, we need to do a self-join of this virtual table to a copy of itself. What we want in this result set is a list of all the consecutive pairs of rows in the table. That query is a hairball -- it puts the structured in structured query language. But it works. Here it is: 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
    

    The whole trick for comparing consecutive rows is the

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

    query pattern. The rownum+1 = rownum thing gathers rows with consecutive row numbers together.

    Next, we need to summarize the result of that query to get the total time logged in for each user. That will work like this:

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

    That looks like this: http://sqlfiddle.com/#!2/bf6ef/5/0

    This is the whole query put together.

    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
    

    It's not real intuitive for somebody used to procedural, algorithmic, thinking. But this is the way you do this kind of consecutive-row comparison in SQL.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算