美好的一天。
我有这样的环境:在Mysql数据库上,每次用户登录某个站点时,都会创建一个新行,包括他的名字和登录时间。由于系统是互斥的,因此在给定时间只有用户,如果新用户到达,则记录的用户将被注销。
现在他们已经要求我计算系统上所有用户的总时间,所以基本上,我必须将登录和下一个用户的所有时差加在一起。
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
我想问你的意见,因为有很多登录,这是计算用户总记录时间的最佳方法?在此示例中,“gamma”将具有56秒的登录时间,并且可以忽略最后一次登录beta,因为它将在执行此检查时在线。所以“beta”只有一个条目。
有没有办法通过查询计算它?或者最好添加一个“在线时间”列,并在每次用户注销在线时间时让系统计算?
答案 0 :(得分:1)
如果要在MySQL中执行此操作,则需要自联接。因为MySQL没有内置的rownum功能,所以自我加入是一件痛苦的事情。但它仍然可行。
首先,我们需要创建一个子查询来创建一个模拟SELECT rownum, user, timestamp FROM login
的虚拟表,我们可以这样做。 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
接下来,我们需要将此虚拟表自我连接到自身的副本。我们在这个结果集中想要的是表中所有连续行对的列表。该查询是一个毛球 - 它将结构化放在结构化查询语言中。但它的确有效。这是: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
比较连续行的整个技巧是
SELECT (virtual_table) AS first
JOIN (virtual_table) AS second ON first.rownum+1 = second.rownum
查询模式。 rownum + 1 = rownum的东西收集连续行号的行。
接下来,我们需要总结该查询的结果,以获取每个用户登录的总时间。这将是这样的:
SELECT user, SUM(timeloggedin) AS timeloggedin
FROM (
/* the self-joined query */
) AS selfjoin
GROUP BY user
ORDER BY user
看起来像这样:http://sqlfiddle.com/#!2/bf6ef/5/0
这是整个查询放在一起。
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
对于习惯于程序,算法,思考的人来说,这并不是真正直观的。但这是你在SQL中进行这种连续行比较的方式。
答案 1 :(得分:1)
试试这个......你的问题的解决方案越来越少......
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
:-)看你星期一!!!