如何获取不同行之间的日期记录?

时间:2014-01-19 20:09:26

标签: mysql

SQL Fiddle

我有一个名为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的在线人员应该返回: Player1Player3

到目前为止我尝试过:

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             |
+------------------------------------------------------+

2 个答案:

答案 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;