繁体   English   中英

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

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

我有表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。

您想要执行一个查询,将同一张表视为两个不同的表,如下所示:

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

那是几秒钟的时间。 您可以随心所欲。 就一天中的多次而言,您的数据库没有具体说明哪些进出时间在一起。 如果可以假定连续的in /​​ out,in / out,那么您将需要对时间进行求和,并需要ORDER BY Date_Time,但是如果没有非常复杂的子查询,就没有明确的方法。

考虑匹配Empl_NameDate的派生表的联接 (后者从datetime字段中拉出)。 每个派生表分别说明“ 超时”记录和“超时”记录。

另外,由于按日期联接会输出所有同一天的组合,因此每天会为这些多个记录集成TimeRank ,但是我们只希望在一天内联接时间段对(开始/结束)。 因此,等级指定了员工签入和签出的第一,第二和以后的时间,并且整天递增。 将这两个集合连接后,外部查询将按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

一种可能的方法是从雇员的分组出发,列出出入清单:

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根据上个月的总天数显示每天的平均小时数。 例如,如果上个月是一月,则将小时数除以31。如果将2月起,将小时数除以28,依此类推。

这是代码,

  1. 这可以解决一天内的多次出入
  2. 此外,它还会比较当天的先进先出

通过将第一个记录作为入站时间,将最后一个记录作为出站时间,并在连接表时使用日期(而非日期时间)来完成此操作

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