这个查询做到了。
SELECT user, CAST(date AS DATE) day, (SUM(worked_seconds) / 60) minutes
FROM (
SELECT w1.user
, w1.date
, UNIX_TIMESTAMP(
LEAST(
MIN(IFNULL(w2.date, w1.date + INTERVAL 5 MINUTE)),
CAST(w1.date AS DATE) + INTERVAL 1 DAY
)
)
- UNIX_TIMESTAMP(w1.date) worked_seconds
FROM work w1
LEFT JOIN work w2
ON w1.user = w2.user
AND w1.date < w2.date
AND w1.date + INTERVAL 5 MINUTE > w2.date
AND CAST(w1.date AS DATE) = CAST(w2.date AS DATE)
GROUP BY w1.user, w1.date
) work
GROUP BY user, day
该查询将每个工作行与同一用户 (ON w1.user = w2.user) 在 5 分钟间隔内 (AND w1.date < w2.data AND w1.date + INTERVAL 5 MINUTE > w2.日期),前提是工作发生在同一天 (CAST(w1.date AS DATE) = CAST(w2.date AS DATE)。
根据定义,在特定日期的最后一行不会有后面的行,并且因为我们使用 LEFT JOIN 这将导致 NULL 值。我们假设对于最后一行,按照注销规则完成了 5 分钟的工作 (IFNULL(w2.date, w1.date + INTERVAL 5 MINUTE)
对于每个(日期,用户)行,可能会找到多个后面的行,在这种情况下,我们希望找到最早的行,以便我们可以计算两个日期之间的差异。这是使用 MIN 函数完成的。
现在,由于最后一行 + 5 分钟间隔可能会超出一天的结束时间,我们使用 LEAST 来防止这种情况。
UNIX_TIMESTAMP 用于将日期时间转换为秒,因此我们可以轻松地减去它们并获得工作秒数。
在外部查询中,最后我们对每个用户的工作求和并除以 60 以获得从秒到分钟的结果。