MySQL版本为 8.0.16
我想获取给定日期的总休息时间,表格如下:
id | employee_id | check_in | check_out
--------------------------------------------------------------
1 | 2103 | 2019-09-15 07:30:00 | 2019-09-15 09:20:00
2 | 2103 | 2019-09-15 10:35:00 | null
3 | 2103 | 2019-09-16 08:00:00 | 2019-09-16 10:00:00
4 | 2103 | 2019-09-16 11:00:00 | 2019-09-16 18:00:00
5 | 2095 | 2019-09-16 08:30:00 | 2019-09-16 18:30:00
我的预期结果
id | employee_id | check_in | check_out | breaks
--------------------------------------------------------------------------
1 | 2103 | 2019-09-15 07:30:00 | null | 75
3 | 2103 | 2019-09-16 08:00:00 | 2019-09-16 18:00:00| 60
5 | 2095 | 2019-09-16 08:30:00 | 2019-09-16 18:30:00| 0
我的查询仅返回雇员ID,日期,first_check_in,last_check_out列
SELECT
a1.employee_id,
cast(a1.check_in as date) AS date,
MIN(a1.check_in) AS first_check_in,
CASE WHEN a2.employee_id IS NULL
THEN MAX(a1.check_out)
ELSE NULL
END AS last_check_out
FROM attendance_employees AS a1
LEFT JOIN attendance_employees AS a2
ON a1.employee_id = a2.employee_id
AND CAST(a1.check_in AS date) = CAST(a2.check_in AS date)
AND a2.check_out IS NULL
WHERE 1 = 1
AND DATE(a1.check_in) in ('2019-09-15', '2019-09-16')
GROUP BY a1.employee_id,
CAST(a1.check_in AS date)
ORDER BY a1.employee_id,
date
有没有一种方法可以计算MySQL的中断时间?谢谢
更新我的完整查询,其中包含预期工作时间和休息时间范围的时间段
SELECT CONCAT(IFNULL(employees.first_name,''),' ',IFNULL(employees.surname,'')) as full_name,
teams.description,
time_periods.start_time as start,
time_periods.end_time as end,
time_periods.time_period_type,
time_groups.name,
cast(a1.check_in as date) AS date,
MIN(a1.check_in) AS first_check_in,
CASE WHEN a2.employee_id IS NULL
THEN MAX(a1.check_out)
ELSE NULL
END AS last_check_out
FROM attendance_employees AS a1
LEFT JOIN attendance_employees AS a2
ON a1.employee_id = a2.employee_id
AND CAST(a1.check_in AS date) = CAST(a2.check_in AS date)
AND a2.check_out IS NULL
JOIN employees
ON employees.id = a1.employee_id
JOIN teams
ON employees.team_id = teams.id
JOIN time_groups
ON teams.time_group_id = time_groups.id
LEFT JOIN day_time_group_time_period
ON time_groups.id = day_time_group_time_period.time_group_id
AND day_time_group_time_period.day_id = 3
LEFT JOIN time_periods
ON day_time_group_time_period.time_period_id = time_periods.id
WHERE 1 = 1
AND DATE(a1.check_in) in ('2019-09-15', '2019-09-16')
GROUP BY a1.employee_id,
CAST(a1.check_in AS date),
a2.employee_id,
time_periods.start_time,
time_periods.end_time,
time_periods.time_period_type
ORDER BY a1.employee_id,
date
给出以下结果:
full_name| start | end | type| name | date | first_check_in | last_check_out
-----------------------------------------------------------------------------------------------------
EMP1 | 08:00:00| 16:30:00| 1 | Day Shift| 2019-09-16| 2019-09-16 08:45:00| 2019-09-16 19:30:00
EMP1 | 10:00:00| 10:30:00| 2 | Day Shift| 2019-09-16| 2019-09-16 08:45:00| 2019-09-16 19:30:00
EMP1 | 12:00:00| 12:30:00| 2 | Day Shift| 2019-09-16| 2019-09-16 08:45:00| 2019-09-16 19:30:00
EMP2 | 08:00:00| 16:30:00| 1 | Day Shift| 2019-09-15| 2019-09-15 07:30:00| NULL
EMP2 | 10:00:00| 10:30:00| 2 | Day Shift| 2019-09-15| 2019-09-15 07:30:00| NULL
EMP2 | 12:00:00| 12:30:00| 2 | Day Shift| 2019-09-15| 2019-09-15 07:30:00| NULL
哪里 类型1用于预期的工作时间范围,并且 类型2用于预期的休息时间范围
答案 0 :(得分:1)
在您最初的问题中,可以使用以下方法:
SELECT dt.employee_id,
Min(dt.check_in) AS check_in,
CASE WHEN COUNT(dt.check_out) = COUNT(*) THEN MAX(dt.check_out)
ELSE NULL
END AS check_out,
Sum(dt.break_interval) AS break_interval
FROM (
SELECT employee_id,
check_in,
check_out,
timestampdiff(minute, Lag(check_out) over w, check_in) AS break_interval
FROM attendance_employees
WHERE check_in BETWEEN '2019-09-15 00:00:00' AND '2019-09-16 23:59:59'
WINDOW w AS (partition BY employee_id, date(check_in) ORDER BY check_in ASC) ) dt
GROUP BY dt.employee_id,
date(dt.check_in);
| employee_id | check_in | check_out | break_interval |
| ----------- | ------------------- | ------------------- | -------------- |
| 2095 | 2019-09-16 08:30:00 | 2019-09-16 18:30:00 | |
| 2103 | 2019-09-15 07:30:00 | | 75 |
| 2103 | 2019-09-16 08:00:00 | 2019-09-16 18:00:00 | 60 |
详细信息:
LAG()
之类的Analytic / Window函数来计算同一日期的雇员的前次 check_out
时间。为此,我们的分区窗口将位于雇员上方,日期为check_in
。分区窗口将按check_in
时间排序,以便LAG()
仅返回前一个条目。TimeStampDiff()
函数在当前行的检入时间和前一行的检出时间之间以分钟为单位确定break_interval
。break_interval
的汇总。另外,如果在特定日期的员工最后一个条目中没有check_out
,那么check_out
时间将需要一些特殊的处理,因为您需要在那里NULL
和MAX(..)
将不会返回NULL
。DATE()
时避免使用check_in
函数并使用Range条件来进行查询sargeable。