计算员工上个月在工作场所每天的平均小时数

时间:2017-03-18 23:39:05

标签: mysql sql

我有表 Time_Periods(Empl_Name,Direction,Date_Time),它存储员工进出的数据。

Empl_Name - 员工的姓名;

方向 - 方向(输入或输出);

Date_Time - 提交操作的日期和时间(详细信息直到秒)。

如果员工进入,那么他必须在同一天离开。 在一天内,员工可以反复进出。

如何撰写一份请求,计算员工上个月在工作场所每天的平均小时数?

更新: 表的例子。

+-----------+-----------+---------------------+
| Empl_Name | Direction | Date_Time           |
+-----------+-----------+---------------------+
| a1        |         1 | 2017-03-18 23:55:59 |
| a1        |         0 | 2017-03-18 23:56:07 |
| a2        |         1 | 2017-03-18 23:56:17 |
| a2        |         0 | 2017-03-18 23:56:22 |
| a3        |         1 | 2017-03-18 23:57:35 |
| a3        |         0 | 2017-03-18 23:57:39 |
+-----------+-----------+---------------------+

预期输出:a1在工作场所花费7/30秒,a2花费5/30秒,a3花费4/30秒。 这意味着我想要为每个员工和工作时间总结 除以30。

4 个答案:

答案 0 :(得分:1)

您希望对同一个表进行查询,就好像它是两个不同的表一样 - 如下所示:

SELECT t1.Empl_Name, TIMEDIFF(t1.Date_Time,t2.Date_Time) AS timein 
FROM empl t1, empl t2 
WHERE t1.Direction='0' AND t2.Direction='1' AND t1.Empl_Name=t2.Empl_Name  
GROUP BY Empl_Name

结果:

Empl_Name timein
A1        00:00:08
A2        00:00:05
A3        00:00:04

那是几秒钟的时间。你可以用你想要的东西。就一天中多次而言,您的数据库并没有具体说明哪些进出时间在一起。如果可以假定连续输入/输出,输入/输出,那么您需要SUM时间和ORDER BY Date_Time,但没有明确的方法可以在没有非常复杂的子查询的情况下执行此操作。

答案 1 :(得分:1)

考虑与 Empl_Name Date (后者从datetime字段中提取)匹配的派生表的连接。每个派生表分别考虑 Time In 记录和 Time Out 记录。

此外, TimeRank 是每天为那些多条记录集成的,因为按日期加入会输出所有当天的组合,但我们只希望在一天内加入时间段配对(开始/结束)。因此,排名指定员工签入和退出的第一次,第二次和后续次数,在所有日期递增。一旦两个集合加入,则外部查询将按 Empl_Name Date 分组,按天计算平均或总时差。

SELECT p1.Empl_Name, DATE_FORMAT(p1.Date_Time_In,'%Y-%m-%d') AS `TimeInDate`, 
       AVG(TIMEDIFF(p1.Date_Time_In, p2.Date_Time_Out)) AS `AvgTimeDiffSecs`,
       SUM(TIMEDIFF(p1.Date_Time_In, p2.Date_Time_Out)) AS `SumTimeDiffSecs` 
FROM
   -- TIME-IN RECORDS
   (SELECT t.Empl_Name, DATE_FORMAT(t.Date_Time,'%Y-%m-%d') AS `TimeInDate`, 
           t.Date_Time As `Date_Time_In`,
           (SELECT Count(*) FROM Time_Periods sub 
            WHERE sub.Date_Time <= t.Date_Time 
            AND sub.Empl_Name = t.Empl_Name
            AND sub.Direction = 0) As TimeInRank       
    FROM Time_Periods t
    WHERE t.Direction=0) As p1

INNER JOIN
   -- TIME-OUT RECORDS
   (SELECT t.Empl_Name, DATE_FORMAT(t.Date_Time,'%Y-%m-%d') AS `TimeInDate`, 
           t.Date_Time As `Date_Time_Out`,
           (SELECT Count(*) FROM Time_Periods sub 
            WHERE sub.Date_Time <= t.Date_Time 
            AND sub.Empl_Name = t.Empl_Name
            AND sub.Direction = 1) As TimeOutRank       
    FROM Time_Periods t
    WHERE t.Direction=1) As p2

ON p1.Empl_Name = p2.Empl_Name AND p1.TimeInRank = p2.TimeOutRank
AND DATE_FORMAT(p1.Date_Time_In,'%Y-%m-%d') = DATE_FORMAT(p2.Date_Time_Out,'%Y-%m-%d')

GROUP BY p1.Empl_Name, DATE_FORMAT(p1.Date_Time_In,'%Y-%m-%d')

-- Empl_Name    TimeInDate  AvgTimeDiffSecs     SumTimeDiffSecs
--        a1    2017-03-18     8.0000000000            8.000000
--        a2    2017-03-18     5.0000000000            5.000000
--        a3    2017-03-18     4.0000000000            4.000000

答案 2 :(得分:1)

一种可能的方法是从员工分组的出入列表开始:

SELECT e.Empl_Name, a.Date_Time coming, b.Date_Time leaving, TIMEDIFF(b.Date_Time, a.Date_Time) AS timein 
FROM empl e
    INNER JOIN empl a ON e.Empl_Name = a.Empl_Name AND a.Direction = 1
    INNER JOIN empl b ON e.Empl_Name = b.Empl_Name AND b.Direction = 0 AND a.Date_Time < b.Date_Time
GROUP BY e.Empl_Name, a.Date_Time 

会给出类似的东西:

+-----------+---------------------+---------------------+----------+
| Empl_Name |       coming        |       leaving       |  timein  |
+-----------+---------------------+---------------------+----------+
| a1        | 2017-03-18 23:55:59 | 2017-03-18 23:56:07 | 00:00:08 |
| a1        | 2017-03-18 23:58:08 | 2017-03-18 23:58:37 | 00:00:29 |
| a2        | 2017-03-18 23:56:17 | 2017-03-18 23:56:22 | 00:00:05 |
| a2        | 2017-03-18 23:58:03 | 2017-03-19 01:30:36 | 01:32:33 |
| a3        | 2017-03-18 23:57:35 | 2017-03-18 23:57:39 | 00:00:04 |
+-----------+---------------------+---------------------+----------+

http://rextester.com/EMZ27244

在下一步中,我们可以将其包装在子查询中以计算上个月的总小时数和每天的平均小时数

SELECT 
    t.Empl_Name, 
    YEAR(CURRENT_DATE - INTERVAL 1 MONTH) last_month_year,
    MONTHNAME(CURRENT_DATE - INTERVAL 1 MONTH) last_month,
    COUNT(DISTINCT DATE(t.coming)) total_days_at_work,
    TIME_TO_SEC(SUM(t.timein)) total_seconds,
    TIME_TO_SEC(SUM(t.timein))/3600 total_hours,
    TIME_TO_SEC(SUM(t.timein))/3600/COUNT(DISTINCT DATE(t.coming)) avg_hours_per_day_worked,
    TIME_TO_SEC(SUM(t.timein))/3600/DAY(LAST_DAY(CURRENT_DATE - INTERVAL 1 MONTH)) avg_hours_per_day_prev_month
    FROM (
        SELECT e.Empl_Name, a.Date_Time coming, b.Date_Time leaving, TIMEDIFF(b.Date_Time, a.Date_Time) AS timein 
        FROM empl e
            INNER JOIN empl a ON e.Empl_Name = a.Empl_Name AND a.Direction = 1
            INNER JOIN empl b ON e.Empl_Name = b.Empl_Name AND b.Direction = 0 AND a.Date_Time < b.Date_Time
        GROUP BY e.Empl_Name, a.Date_Time 
    ) t
WHERE YEAR(t.coming) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(t.coming) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
GROUP BY t.Empl_Name;

结果:

+-----------+-----------------+------------+--------------------+---------------+-------------+--------------------------+------------------------------+
| Empl_Name | last_month_year | last_month | total_days_at_work | total_seconds | total_hours | avg_hours_per_day_worked | avg_hours_per_day_prev_month |
+-----------+-----------------+------------+--------------------+---------------+-------------+--------------------------+------------------------------+
| a1        |            2017 | February   |                  1 |            37 |      0.0103 |               0.01027778 |                   0.00036706 |
| a2        |            2017 | February   |                  2 |         22538 |      6.2606 |               3.13027778 |                   0.22359127 |
| a3        |            2017 | February   |                  1 |             4 |      0.0011 |               0.00111111 |                   0.00003968 |
+-----------+-----------------+------------+--------------------+---------------+-------------+--------------------------+------------------------------+

http://rextester.com/FNQH14731

编辑:更新了示例查询,还包括员工上个月工作的总天数。

avg_hours_per_day_worked显示上个月每个工作日的平均小时数。

avg_hours_per_day_prev_month根据上个月的总天数显示每天的平均小时数。例如,如果前一个月是1月,则小时数除以31.如果是Februari,除以28,依此类推。

答案 3 :(得分:1)

这是代码,

  1. 这解决了一天内的多次进出
  2. 此外,它比较同一天的第一个和最后一个
  3. 这是通过将第一个记录作为时间和最后一个记录作为输出时间并在加入表时使用日期(而不是日期时间)来完成的

    select t1.Empl_Name, 
           sum (Seconds_per_day)/count(distinct date_id) as average_seconds
    from 
    ( 
    SELECT t1.Empl_Name, 
           t1.cast(t1.Date_Time AS DATE) as date_id, 
           DATEDIFF(second,min(t1.Date_Time),max(t2.Date_Time)) AS Seconds_per_day 
    FROM empl as t1
    inner join  empl as t2 
    on t1.Direction='0' AND t2.Direction='1' 
       AND t1.Empl_Name=t2.Empl_Name
       and CAST(t1.Date_Time AS DATE) = CAST(t2.Date_Time AS DATE)
    GROUP BY Empl_Name, t1.cast(t1.Date_Time AS DATE)
    )
    group by  t1.Empl_Name