开发者

MySQL Calculate Time Online

Would it be possible to calculate time online from a table of something like

logtype   time  
----------------
login     2:30  
logout    2:45  
login     3:20  
logout    4:50  
login     5开发者_运维百科:00  
login     5:10  
logout    6:00  

It would have extra logins because sometimes the server crashes and doesn't add logout. Can you do something like this in MySQL only or would you have to use possibly ColdFusion? And if so, how would you do it in MySQL/ColdFusion?

All I'm wanting is a (rough) total of time online, hours, days, minutes etc for a particular user.


(See my notes above first, please.)

For the data that you would have, however, by pairing consecutive login/logout pairs, you could process the data to get the information that you need just using a simple dateDiff([datepart], [date 1], [date 2]) function in CF to figure out the difference, if you had already queried the data.

For the data handling, I would suggest adding another row to your table -- one that handles a Session ID. This will ensure proper pairing of your login/logout times. You then could set up your queries something like the following:

<cfquery name="getSession" datasource="[dsn]">
   SELECT DISTINCT sessionID
   FROM logTable
   WHERE userID = <cfqueryparam cfsqltype="cf_sql_integer" value="[inputted userID]" />
</cfquery>

...then, to get the individual login sessions' login times, run a loop like this to output them...

<cfoutput query="getSessions">
   <cfquery name="getSessionInfo" datasource="[dsn]">
      SELECT 
      (SELECT time 
         FROM logTable 
         WHERE sessionID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#getSessions.sessionID# />
         AND logType = <cfqueryparam cfsqltype="cf_sql_varchar" value="login" />)
      AS loginTime,
      (SELECT time 
         FROM logTable 
         WHERE sessionID = <cfqueryparam cfsqltype="cf_sql_varchar" value="#getSessions.sessionID# />
         AND logType = <cfqueryparam cfsqltype="cf_sql_varchar" value="logout" />)
      AS logoutTime
      FROM logTable
   </cfquery>

   [ancillary output - use your DateDiff here with getSessionInfo.loginTime and getSessionInfo.logoutTime as your two date/times and use the data as you need]
</cfoutput>

My SQL on this may be a little off, but at least it points you in the right direction... Hope this helps... feel free to contact me off-list for more explanation.


As others have suggested, modifying the table structure is a better approach in the long run. Trying to pair up log records (with no matching key) is difficult, and sometimes impossible. A slightly modified structure would be easier to query, and would yield more accurate results. However, if you absolutely cannot modify the table, it might be possible to calculate a rough total - IF your record ID is numeric/sequential.

The assumption is a "logout" record is always inserted after a "login". So the logout's record ID would always be greater than that of the corresponding "login". A subquery could convert the login information into pairs: ie current and next login record. The corresponding "logout" record id would fall within that range. Once you have matched up login/logouts, use date/time functions to calculate the time elapsed in minutes. Then SUM() the values and format the results however you wish. Note: Obviously proper indexing of the table is a must.

That said, this method only provides an estimate. It has several flaws:

  • Some databases do not optimize subqueries very well. So even with indexes, the query performance can be quite poor if there is a lot of data involved.
  • Relies solely upon the record id for identification.
  • Does not account for stray logout records or erroneous/duplicates. So it may be less accurate than other methods
  • Requires more convoluted sql than alternative structures

Anyway, I am not sure of the MySQL syntax off the top of my head. But ignoring the MS Sql Server specific functions, this should be close. The performance in MS SQL was decent with proper indexes, and about 100K records.

SELECT  SUM(DateDiff(n, li.LogTime, lo.LogTime)) AS TotalTimeInMinutes
FROM    (
            SELECT  li.RecordID, li.UserID, li.LogType, li.LogTime,
                   (    SELECT MIN(t.RecordID) FROM  YourTable t
                        WHERE t.UserID   = li.UserID
                        AND   t.LogType  = li.logType
                        AND   t.RecordID > li.RecordID
                    ) AS NextRecordID
            FROM   YourTable li
            WHERE  li.UserID = 123
            AND    li.LogType = 'login'
        ) 
        li INNER JOIN YourTable lo ON lo.UserID = li.UserID
             AND lo.LogType = 'logout'
             AND lo.RecordID BETWEEN li.RecordID AND li.NextRecordID


In my current project I'm using a bit another definition of the "user activity". For me this is period between session star and last page request. I'm not tracking activity time in exactly this format, but if I needed to -- I would make it this way.

When session starts -- create entry in the table sessions which may look like this:

id (int) auto-incremented PK
sessionid (varchar) -- optional, session id string from ColdFusion
userid (int) FK
session_start (datetime) -- filled when created
last_request (datetime)

Primary key is stored into the user session when entry created.

When user makes request -- update the last_request attribute.

It is also possible to update this when onSessionEnd fired, but you'll need to substract the session timeout from current time to get the last request moment -- which makes this useless.

Additional benefit of this approach is that you can get the aggregated data per user very easily. For example, this will select number of seconds (not tested, may be buggy):

<cfquery datasource="mydsn" name="qGetUserData">
    select userid, sum(unix_timestamp(last_request) - unix_timestamp(session_start)) as timespan
    from sessions 
    group by userid
</cfquery>

Filtering by period is easy too -- simply add where session_start ... clause, same for filtering by specific user(s).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜