2013-03-25 45 views
0

我有一个表格式如下:用户“分钟工作”。如何使这个查询?

id, user, action, date 
1, user1, a1, 2013-03-20 10:00:01 
2, user2, a1, 2013-03-20 10:00:03 
3, user2, a1, 2013-03-20 10:00:12 
4, user3, a1, 2013-03-20 10:00:20 
5, user2, a1, 2013-03-20 10:00:24 
.... 
... 

,并继续在所有分钟和小时(全天候)与30型动物的用户...

现在我需要知道“分钟的工作” .. 。例如:

  1. 如果我只有一个用户全天,我有24小时* 60分钟= 1440分钟 今天工作。
  2. 如果是全天(24小时)2级的用户将是:2880分钟 工作...

但是......用户不要整天工作(当然..)我怎么能做出这种查询?

解答一些问题:

  • 我需要(从所有 用户分钟的总和)得到所有用户的分钟的工作
  • 我asume“注销”的用户,如果他们不在5分钟内做任何动作。
  • 我可以使用一些PHP代码来完成这项工作。
+4

[你有什么尝试?](http://www.whathaveyoutried.com/)请参见[ask advice](http://stackoverflow.com/questions/ask-advice)。 – 2013-03-25 02:23:39

+0

预期产量是多少?你只是想总结给定用户至少工作一次的所有分钟吗? – Patashu 2013-03-25 02:29:19

+0

所以你有一个表记录他们所有的行为?你如何定义用户何时停止工作?如果他们还没有在30分钟内做出行动?或者是在任何一天的第一次和最后一次行动之间的时间跨度? – mpen 2013-03-25 02:29:42

回答

1

此查询的确如此。

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 

在5分钟间隔内的查询对每个工作行具有相同的用户的所有后来的工作行(ON w1.user = w2.user)(AND w1.date < w2.data AND w1.date + INTERVAL 5 MINUTE> w2.date),前提是工作发生在同一天(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,以便从秒到分钟。