我有一个名为Event
的表,当多人游戏服务器上的玩家登录和注销时会记录。
+----------------------------------------------+
| id | username | type | timestamp |
+----------------------------------------------+
| 1 | Player3 | login | 2014-01-14 17:00:00 |
| 2 | Player4 | login | 2014-01-14 17:00:00 |
| 3 | Player4 | logout | 2014-01-14 17:30:00 |
| 4 | Player1 | login | 2014-01-14 18:00:00 |
| 5 | Player2 | login | 2014-01-14 19:00:00 |
| 6 | Player3 | logout | 2014-01-14 19:00:00 |
| 7 | Player1 | logout | 2014-01-14 20:00:00 |
| 8 | Player2 | logout | 2014-01-14 20:00:00 |
+----------------------------------------------+
我想为在特定时间戳上线的用户提供唯一的用户名列表。例如,如果我想知道2014-01-14 18:00:00
的在线人员应该返回:
Player1
和Player3
。
到目前为止我尝试过:
SELECT * FROM event
WHERE (timestamp <= '2014-01-14 18:00:00' AND type = 'login')
AND (timestamp >= '2014-01-14 18:00:00' AND type = 'logout');
EDIT2:
Session
表:
+------------------------------------------------------+
| id | login_event | logout_event | duration (seconds) |
+------------------------------------------------------+
| 1 | 1 | 6 | xxxxxx |
| 2 | 2 | 3 | xxxxxx |
| 3 | 4 | 7 | xxxxxx |
| 4 | 5 | 8 | xxxxxx |
+------------------------------------------------------+
答案 0 :(得分:2)
这对您的查询来说更复杂。你需要那些当时最近的行动是登录的人,基本上是:
SELECT username,
max(case when type = 'login' and timestamp <= '2014-01-14 18:00:00'
then timestamp
end) as lastlogin,
max(case when type = 'logout' and timestamp <= '2014-01-14 18:00:00'
then timestamp
end) as lastlogout
FROM event
GROUP BY username
HAVING (lastlogout is null or lastlogout < lastlogin) and lastlogin is not null;
编辑:
顺便说一句,如果你知道登录/注销记录是完全准确的(从不错过,从不重复),你也可以用计数(有些人可能会发现更容易理解)来做到这一点:
SELECT username,
sum(type = 'login' and timestamp <= '2014-01-14 18:00:00') as numlogins,
sum(type = 'logout' and timestamp <= '2014-01-14 18:00:00') as numlogouts
FROM event
GROUP BY username
HAVING numlogins > numlogouts;
编辑(会议上):
会话表上的查询看起来更容易:
SELECT lie.username
from session s join
event lie
on s.login_event = lie.id join
event loe
on s.logout_event = loe.id
where lie.timestamp <= '2014-01-14 18:00:00' and
loe.timestamp >= '2014-01-14 18:00:00';
这很有效,在小桌子上可能会更好。在较大的桌子上,我认为它不会那么好用。什么是有效的是一个会话表,其中包含两个时间戳,并带有索引。
答案 1 :(得分:0)
SELECT username FROM
(SELECT username,timestamp as intime,
(SELECT min(timestamp)
FROM event e2
WHERE e2.username = e1.username
AND e2.timestamp > e1.timestamp
AND e2.type = 'logout') as outtime
FROM event e1
WHERE e1.type = 'login'
)t1
WHERE '2014-01-14 18:00:00' BETWEEN t1.intime AND t1.outtime;
您可以将时间戳配对为时间和时间,然后查看您指定的时间是否在这些时间之间。 sqlFiddle
或者您可以使用HAVING
取出1级子查询。
SELECT username,timestamp as intime,
(SELECT min(timestamp)
FROM event e2
WHERE e2.username = e1.username
AND e2.timestamp > e1.timestamp
AND e2.type = 'logout') as outtime
FROM event e1
WHERE e1.type = 'login'
HAVING '2014-01-14 18:00:00' BETWEEN intime AND outtime;