我正在查询MySQL数据库中的一个非常大的活动日志,试图弄清楚每个用户在某一天的午夜做了什么。问题是我只对可能的日志消息的子集感兴趣,并且我希望在午夜之前该子集中的最后一个日志条目。这是我到目前为止所做的:
SELECT user, dateAndTime, msg
FROM Log
WHERE msg in ('off', 'on', 'sleep', 'wake')
AND logDate = '2011-12-31';
ORDER BY user ASC, dateAndTime DESC
(我们将用户和消息称为类型VARCHAR
,将日期定义为DATE
,将dateAndTime定义为DATETIME
。)
这似乎是一个很好的第一步。结果按用户名显示在组中,并按时间排序。 有没有办法为每个用户提供这些结果的第一行?我总是可以对结果进行后期处理,但这似乎是我应该能够对查询本身做的事情。我很想在集合中而不是在程序上思考,所以如果解决方案应该是显而易见的,我会事先道歉。
附加说明......
我在SO上发现了许多其他问题来处理同样的问题,但是我的额外限制使得它变得更加困难。我尝试修改this query,但我认为GROUP BY
条款在某种程度上失去了对msg
的限制。
我也在时间限制下工作。查询通过一个Web服务(我无法控制),在5分钟后自动超时。 Log表很大(2011-12-31只有近200万行),因此我尝试涉及的大多数解决方案只是超时。
更新
我发现了一些我之前不知道的数据。对于给定的dateAndTime
,每个用户有多行。
答案 0 :(得分:4)
SELECT l.user, l.dateAndTime, l.msg
FROM Log l
INNER JOIN (SELECT user, MAX(dateAndTime) AS MaxDateTime
FROM log
WHERE msg in ('off', 'on', 'sleep', 'wake')
AND logDate = '2011-12-31'
GROUP BY user) q
ON l.user = q.user
AND l.dateAndTime = q.MaxDateTime
WHERE l.msg in ('off', 'on', 'sleep', 'wake')
ORDER BY l.user ASC
答案 1 :(得分:1)
警告:不保证始终有效,但应该很快:
select * from
(SELECT user, dateAndTime, group_concat(msg) allMsgs
FROM Log
WHERE msg in ('off', 'on', 'sleep', 'wake')
AND logDate = '2011-12-31'
GROUP BY user, dateAndTime
ORDER BY user ASC, dateAndTime DESC) v
group by user
在MySQL中,既不聚合也不分组的列仍可包含在分组查询的select子句中。根据MySQL文档,这些列不是保证是组中任何特定行的值(因为这是一个包含功能依赖于 em>分组),但通常似乎是组内访问的第一个值。此功能很容易受到查询计划中的更改的影响,这就是为什么所有排序都在内联视图中进行的原因 - 因此分组应该发生在查询部分之外,可以通过查询计划中的更改进行更改。
答案 2 :(得分:0)
SELECT log.user, log.msg, log.dateAndTime
FROM(
SELECT user, msg, max(dateAndTime) as maxdatetime
FROM Log
WHERE msg in ('off', 'on', 'sleep', 'wake')
AND logDate = '2011-12-31';
GROUP BY user, msg
) inner, Log log
WHERE log.user = inner.user
AND log.msg = inner.msg
AND log.dateAndTime = inner.maxdatetime
ORDER BY log.user ASC, log.dateAndTime DESC