简体   繁体   English

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

[英]calculate the average number of hours per day that the employee spent on the workplace for the previous month

I have table Time_Periods (Empl_Name, Direction, Date_Time) , which stores data on the entry and exit of employees. 我有表Time_Periods(Empl_Name,Direction,Date_Time) ,该表存储有关雇员进出的数据。

Empl_Name - the name of the employee; Empl_Name-雇员的姓名;

Direction - Direction (Input or Output); 方向 -方向(输入或输出);

Date_Time - The date and time the action was committed (detailed until a second). Date_Time-提交操作的日期和时间(详细信息直到一秒钟)。

If the employee enters, then he necessarily leaves on the same day. 如果员工进入,那么他必然在同一天离开。 Within one day the employee can repeatedly enter and leave. 员工可以在一天之内反复进入和离开。

How to write a request that will calculate the average number of hours per day that the employee spent on the workplace for the previous month? 如何编写一个请求来计算员工上个月在工作场所每天平均工作的时间?

UPDATE: Example of table. 更新:表的示例。

+-----------+-----------+---------------------+
| 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 |
+-----------+-----------+---------------------+

Expected output: a1 spent on the workplace 7/30 secs, a2 spent 5/30 secs, a3 spent 4/30 secs. 预期的输出:a1在工作场所花费7/30秒,a2在工作场所花费5/30秒,a3在工作场所花费4/30秒。 That is mean that I want to sum work time for every employee and divide by 30. 这意味着我想将每个员工的工作时间相加并除以30。

You want to do a query treating the same table as if it were two different tables - as follows: 您想要执行一个查询,将同一张表视为两个不同的表,如下所示:

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

Results: 结果:

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

Those are the times in seconds. 那是几秒钟的时间。 You can what you want with those. 您可以随心所欲。 As far as multiple times in a day, your database does not specifically say which in and out times go together. 就一天中的多次而言,您的数据库没有具体说明哪些进出时间在一起。 If one can assume consecutive in/out, in/out, then you'd need SUM the times and ORDER BY Date_Time but there is no clear way to do this without a very complicated sub-query. 如果可以假定连续的in /​​ out,in / out,那么您将需要对时间进行求和,并需要ORDER BY Date_Time,但是如果没有非常复杂的子查询,就没有明确的方法。

Consider a join of derived tables matching Empl_Name and Date (latter pulled from datetime field). 考虑匹配Empl_NameDate的派生表的联接 (后者从datetime字段中拉出)。 Each derived table accounts for Time In records and Time Out records respectively. 每个派生表分别说明“ 超时”记录和“超时”记录。

Also, a TimeRank is integrated for those multiple records per day since a join by date outputs all same day combinations but we only want time period pairings (start/end) joined within a day. 另外,由于按日期联接会输出所有同一天的组合,因此每天会为这些多个记录集成TimeRank ,但是我们只希望在一天内联接时间段对(开始/结束)。 Hence, a rank specifies the first, second, and onward times employee checks in and out, incrementing across all days. 因此,等级指定了员工签入和签出的第一,第二和以后的时间,并且整天递增。 Once the two sets are joined then outer query aggregates grouping by Empl_Name and Date for average or total time differences by day. 将这两个集合连接后,外部查询将按Empl_NameDate汇总分组,以按天计算平均或总时间差。

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

One possible approach is to start with a list of coming and leaving, grouped by employees: 一种可能的方法是从雇员的分组出发,列出出入清单:

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 

Would give something like: 将给出类似的内容:

+-----------+---------------------+---------------------+----------+
| 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 http://rextester.com/EMZ27244

In the next step we could wrap it in a subquery to calculate the total hours and the average hours per day for the previous month : 在下一步中,我们可以将其包装在子查询中,以计算上个月的总小时数和每天平均小时数

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;

Result: 结果:

+-----------+-----------------+------------+--------------------+---------------+-------------+--------------------------+------------------------------+
| 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 http://rextester.com/FNQH14731

EDIT: Updated the example query to also include the total number of days the employee was at work the previous month. 编辑:更新了示例查询,还包括该雇员上个月上班的总天数。

avg_hours_per_day_worked shows the average number of hours per worked day the previous month. avg_hours_per_day_worked显示上个月每个工作日的平均小时数。

avg_hours_per_day_prev_month shows the average number of hours per day based on the total number of days the previous month. avg_hours_per_day_prev_month根据上个月的总天数显示每天的平均小时数。 For example if the previous month is January, the hours are divided by 31. If Februari, divided by 28 and so on. 例如,如果上个月是一月,则将小时数除以31。如果将2月起,将小时数除以28,依此类推。

Here is the code, 这是代码,

  1. This solves the multiple ins and outs within a day 这可以解决一天内的多次出入
  2. Also, it compares the first in and the last out for the same day 此外,它还会比较当天的先进先出

This is done by taking the first record as the in time and the last record as the out time and using date (and not datetime) while joining the tables 通过将第一个记录作为入站时间,将最后一个记录作为出站时间,并在连接表时使用日期(而非日期时间)来完成此操作

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM