Domanda

i have a table in mysql to log user actions. Each row in the table corresponds to a user action, like login, logout etc.

The table looks like:

CREATE TABLE IF NOT EXISTS `user_activity_log` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`action_type` smallint NOT NULL,
`action_created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin;


id  user_id  action_type    action_created
...
22    6        1        2013-07-21 14:31:14
23    6        2        2013-07-21 14:31:16
24    8        2        2013-07-21 14:31:18
25    8        1        2013-07-21 14:45:18
26    8        0        2013-07-21 14:45:25
27    8        1        2013-07-21 14:54:54
28    8        2        2013-07-21 15:09:11
29    6        1        2013-07-21 15:09:17
30    6        2        2013-07-21 15:09:29
...

Imagine the action 1 is login and 2 is logout and that i want to find out the total time (in hours:minutes:seconds) the user with id 6 was logged in within a specific range of dates.

My first idea was to fetch all rows with either action 1 or 2 and calculate the date differences in PHP myself. This seems rather complicated and i am sure this can be done in one query with mysql, too!

What i tried was this:

SELECT TIMEDIFF(ual1.action_created, ual2.action_created) FROM user_activity_log
ual1,user_activity_log ual2  WHERE ual1.user_id = 6 AND ual2.user_id = 6 AND
ual1.action_type = 1 AND ual2.action_type = 2 AND
DATE(ual1.action_created) >= '2013-07-21' AND
DATE(ual1.action_created) <= '2013-07-21'
ORDER BY ual1.action_created

to select all login events from ual1 and all logout events from ual2 from the same user and then calculate the pairwise time difference for day 2013.7.21, which does not really work and i don't know why.

How can i calculate the total login time (sum over all time differences, date action 2 - date action 1)? The result from the correct operation should be 2 seconds from log id pair 22,23 + 12 seconds from log id pair 29,30 = 14 seconds.

Thank you very much for your help in advance. Best regards

È stato utile?

Soluzione

I think the easiest way to structure this type of query is using correlated subqueries (and, to be honest, I generally don't like correlated subqueries, but this is an exception). Your query would probably work with the right group by clause.

Here is an alternative method:

select TIMEDIFF(action_created, LogoutTS)
from (select ual.*,
             (select ual2.user_activity_log
              from user_activity_log ual2
              where ual2.user_id = ual.user_id and
                    ual2.action_type = 2 and
                    ual2.action_created > ual.action_created
              order by ual2.action_created desc
              limit 1
             ) as LogoutTS
      from user_activity_log ual
      where ual.user_id = 6 and
            ual.action_type = 1
     ) ual

To get the total, you then need to do something like sum(TIMEDIFF(action_created, LogoutTS). However, this can depend on the format of the time column. It might look something like this:

select SUM((UNIX_TIMESTAMP(LogoutTS) - UNIX_TIMESTAMP(action_created))/1000)

Or:

select sec_to_time(SUM((UNIX_TIMESTAMP(LogoutTS) - UNIX_TIMESTAMP(action_created))/1000))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top