MySQL查询需求:基于单表列类型计算时长差值总和
计算tblStaffLog表中基于LogType的时间差小时总和
看起来你需要统计员工操作日志里,对应操作类型的时间差总小时数对吧?结合你给出的tblStaffLog表结构,我整理了两种实用的MySQL查询方案,分别适配不同版本的MySQL:
方案1:用窗口函数(MySQL 8.0及以上适用)
如果你的MySQL是8.0或更高版本,用LEAD()窗口函数会非常方便——它能帮我们快速获取同一个用户下,按时间排序的下一条操作记录。假设你的LogType是类似IN(登录)和OUT(登出)这种成对的操作类型,直接用下面的查询:
SELECT UserName, SUM(TIMESTAMPDIFF(HOUR, LogTime, NextLogTime)) AS TotalHours FROM ( SELECT UserName, LogType, LogTime, -- 获取当前记录的下一条操作时间 LEAD(LogTime) OVER (PARTITION BY UserName ORDER BY LogTime) AS NextLogTime, -- 获取下一条操作的类型 LEAD(LogType) OVER (PARTITION BY UserName ORDER BY LogTime) AS NextLogType FROM tblStaffLog ) AS sub -- 只筛选登录后紧跟登出的有效配对 WHERE LogType = 'IN' AND NextLogType = 'OUT' GROUP BY UserName;
这个查询的逻辑很清晰:子查询先给每条记录匹配它的下一条操作记录,外层只保留登录和登出的有效配对,计算每对的时间差(转成小时),最后按用户求和总时长。
方案2:自连接(兼容MySQL 5.x等低版本)
如果你的MySQL版本不支持窗口函数,用自连接也能实现需求。我们需要把每个登录记录和它对应的最早登出记录关联起来,同时确保中间没有其他操作干扰:
SELECT s1.UserName, SUM(TIMESTAMPDIFF(HOUR, s1.LogTime, s2.LogTime)) AS TotalHours FROM tblStaffLog s1 JOIN tblStaffLog s2 ON s1.UserName = s2.UserName AND s2.LogType = 'OUT' AND s2.LogTime > s1.LogTime -- 确保两条记录之间没有其他登录/登出操作,保证是配对的 AND NOT EXISTS ( SELECT 1 FROM tblStaffLog s3 WHERE s3.UserName = s1.UserName AND s3.LogTime BETWEEN s1.LogTime AND s2.LogTime AND s3.LogType IN ('IN', 'OUT') AND s3.SlNo NOT IN (s1.SlNo, s2.SlNo) ) WHERE s1.LogType = 'IN' GROUP BY s1.UserName;
一些需要注意的细节
- 记得根据你的实际业务调整
LogType的取值(比如你的业务里可能是Login/Logout,不是IN/OUT) - 如果需要按其他维度统计(比如按
PageName或Extension),只需要修改分组条件(窗口函数的PARTITION BY,或者自连接的关联条件) - 如果存在未配对的记录(比如只有登录没有登出,或者反之),上面的查询会自动忽略这些记录;如果需要处理这种情况,可以改成
LEFT JOIN并对NULL值做特殊处理
内容的提问来源于stack exchange,提问作者Sudhakaran Packianathan
相关产品推荐
相关产品推荐

