我有表 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。
答案 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 |
+-----------+---------------------+---------------------+----------+
在下一步中,我们可以将其包装在子查询中以计算上个月的总小时数和每天的平均小时数:
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)
这是代码,
这是通过将第一个记录作为时间和最后一个记录作为输出时间并在加入表时使用日期(而不是日期时间)来完成的
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