出勤:获得 time_in 和 time_out 的弹性时间表员工
Attendance: Get time_in and time_out of flexible schedule Employees
根据下面给定的模式,我想查询数据库中员工的每日时间 in/out。
注意:员工的工作时间是灵活的,他们可以上夜班或白班(正如您在员工 #1 中看到的那样)。
架构:出勤率table
| id | employee_id | timedata | in_out |
|----|-------------|---------------------|--------|
| 1 | 1 | 2017-06-08 13:51:02 | IN | <- night shift ( inserted: 2017-06-08)
| 2 | 1 | 2017-06-09 01:10:04 | OUT | <- actual time_out (inserted: 2017-06-09)
| 3 | 1 | 2017-06-09 14:11:40 | IN |
| 4 | 1 | 2017-06-09 19:41:26 | OUT |
| 5 | 2 | 2017-06-08 09:25:17 | IN |
| 6 | 2 | 2017-06-08 20:44:14 | OUT |
| 7 | 2 | 2017-06-09 11:35:00 | IN |
| 8 | 2 | 2017-06-09 20:36:06 | OUT |
这是我到目前为止完成的查询:
SELECT employee_id,
DATE(timedata) as attendance_date,
MIN(IF(in_out='IN',timedata,NULL)) AS time_in,
MAX(IF(in_out='OUT',timedata,NULL)) AS time_out
FROM attendances
GROUP BY employee_id,DATE(timedata)
此查询的问题是我无法获取夜班交易的 time_out。这是输出:
| employee_id | attendance_date | time_in | time_out |
|-------------|-----------------|---------------------|---------------------|
| 1 | 2017-06-08 | 2017-06-08 13:51:02 | NULL |
| 2 | 2017-06-08 | 2017-06-08 11:25:17 | 2017-06-08 20:44:14 |
| 2 | 2017-06-09 | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 |
| 1 | 2017-06-09 | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 |
这是我的
期望输出
| employee_id | attendance_date | time_in | time_out |
|-------------|-----------------|---------------------|---------------------|
| 1 | 2017-06-08 | 2017-06-08 13:51:02 | 2017-06-09 01:10:04 |
| 2 | 2017-06-08 | 2017-06-08 09:25:17 | 2017-06-08 20:44:14 |
| 1 | 2017-06-09 | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 |
| 2 | 2017-06-09 | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 |
如有任何建议,我们将不胜感激。
如果不使用分析函数,这个问题将很难处理,MySQL 不支持开箱即用。但是,我们可以使用会话变量模拟 ROW_NUMBER
。这里的一种方法是根据 IN
和 OUT
在 table 中的时间升序并置来对其进行分组。考虑以下查询:
SET @row_number = 0;
SET @emp_id = NULL;
SELECT
t.employee_id,
DATE(MAX(CASE WHEN in_out = 'IN' THEN timedata END)) AS attendance_date,
MAX(CASE WHEN in_out = 'IN' THEN timedata END) AS time_in,
MAX(CASE WHEN in_out = 'OUT' THEN timedata END) AS time_out
FROM
(
SELECT *,
@row_number:=CASE WHEN @emp_id = employee_id THEN @row_number + 1 ELSE 0 END AS rn,
TRUNCATE(@row_number / 2, 0) AS rn_grp,
@emp_id:=employee_id
FROM Attendances
ORDER BY employee_id, timedata
) t
GROUP BY t.employee_id, t.rn_grp;
要查看其工作原理,我生成的行号将使您的原始 table 如下所示:
| id | employee_id | timedata | in_out | rn_grp |
|----|-------------|---------------------|--------|--------|
| 1 | 1 | 2017-06-08 13:51:02 | IN | 0 |
| 2 | 1 | 2017-06-09 01:10:04 | OUT | 0 |
| 3 | 1 | 2017-06-09 14:11:40 | IN | 1 |
| 4 | 1 | 2017-06-09 19:41:26 | OUT | 1 |
| 5 | 2 | 2017-06-08 09:25:17 | IN | 0 |
| 6 | 2 | 2017-06-08 20:44:14 | OUT | 0 |
| 7 | 2 | 2017-06-09 11:35:00 | IN | 1 |
| 8 | 2 | 2017-06-09 20:36:06 | OUT | 1 |
现在应该清楚了,我们可以按 employee_id
和 rn_grp
列分组,然后在您的原始问题中使用数据透视查询方法。
请注意,如果员工数据可能具有 IN
值而没有对应的 OUT
值,则此方法可能不起作用。
输出:
此处演示:
您可以使用自联接将 time_in 与 time_out 合并,其中 time_out 在 time_in 之后。然后按 time_in 分组,然后只选择第一个 time_out:
select employee_id, attendance_date, time_in, MIN(time_out) time_out from (
select A.id id, DATE(A.timedata) attendance_date, A.employee_id employee_id, A.timedata time_in, A.in_out, B.timedata time_out
from attendances A
left join attendances B
on A.employee_id = B.employee_id
and A.timedata < B.timedata
and B.in_out = 'OUT'
where A.in_out = 'IN'
) AB
group by employee_id, attendance_date, time_in
根据下面给定的模式,我想查询数据库中员工的每日时间 in/out。
注意:员工的工作时间是灵活的,他们可以上夜班或白班(正如您在员工 #1 中看到的那样)。
架构:出勤率table
| id | employee_id | timedata | in_out |
|----|-------------|---------------------|--------|
| 1 | 1 | 2017-06-08 13:51:02 | IN | <- night shift ( inserted: 2017-06-08)
| 2 | 1 | 2017-06-09 01:10:04 | OUT | <- actual time_out (inserted: 2017-06-09)
| 3 | 1 | 2017-06-09 14:11:40 | IN |
| 4 | 1 | 2017-06-09 19:41:26 | OUT |
| 5 | 2 | 2017-06-08 09:25:17 | IN |
| 6 | 2 | 2017-06-08 20:44:14 | OUT |
| 7 | 2 | 2017-06-09 11:35:00 | IN |
| 8 | 2 | 2017-06-09 20:36:06 | OUT |
这是我到目前为止完成的查询:
SELECT employee_id,
DATE(timedata) as attendance_date,
MIN(IF(in_out='IN',timedata,NULL)) AS time_in,
MAX(IF(in_out='OUT',timedata,NULL)) AS time_out
FROM attendances
GROUP BY employee_id,DATE(timedata)
此查询的问题是我无法获取夜班交易的 time_out。这是输出:
| employee_id | attendance_date | time_in | time_out |
|-------------|-----------------|---------------------|---------------------|
| 1 | 2017-06-08 | 2017-06-08 13:51:02 | NULL |
| 2 | 2017-06-08 | 2017-06-08 11:25:17 | 2017-06-08 20:44:14 |
| 2 | 2017-06-09 | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 |
| 1 | 2017-06-09 | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 |
这是我的
期望输出
| employee_id | attendance_date | time_in | time_out |
|-------------|-----------------|---------------------|---------------------|
| 1 | 2017-06-08 | 2017-06-08 13:51:02 | 2017-06-09 01:10:04 |
| 2 | 2017-06-08 | 2017-06-08 09:25:17 | 2017-06-08 20:44:14 |
| 1 | 2017-06-09 | 2017-06-09 14:11:40 | 2017-06-09 19:41:26 |
| 2 | 2017-06-09 | 2017-06-09 11:35:00 | 2017-06-09 20:36:06 |
如有任何建议,我们将不胜感激。
如果不使用分析函数,这个问题将很难处理,MySQL 不支持开箱即用。但是,我们可以使用会话变量模拟 ROW_NUMBER
。这里的一种方法是根据 IN
和 OUT
在 table 中的时间升序并置来对其进行分组。考虑以下查询:
SET @row_number = 0;
SET @emp_id = NULL;
SELECT
t.employee_id,
DATE(MAX(CASE WHEN in_out = 'IN' THEN timedata END)) AS attendance_date,
MAX(CASE WHEN in_out = 'IN' THEN timedata END) AS time_in,
MAX(CASE WHEN in_out = 'OUT' THEN timedata END) AS time_out
FROM
(
SELECT *,
@row_number:=CASE WHEN @emp_id = employee_id THEN @row_number + 1 ELSE 0 END AS rn,
TRUNCATE(@row_number / 2, 0) AS rn_grp,
@emp_id:=employee_id
FROM Attendances
ORDER BY employee_id, timedata
) t
GROUP BY t.employee_id, t.rn_grp;
要查看其工作原理,我生成的行号将使您的原始 table 如下所示:
| id | employee_id | timedata | in_out | rn_grp |
|----|-------------|---------------------|--------|--------|
| 1 | 1 | 2017-06-08 13:51:02 | IN | 0 |
| 2 | 1 | 2017-06-09 01:10:04 | OUT | 0 |
| 3 | 1 | 2017-06-09 14:11:40 | IN | 1 |
| 4 | 1 | 2017-06-09 19:41:26 | OUT | 1 |
| 5 | 2 | 2017-06-08 09:25:17 | IN | 0 |
| 6 | 2 | 2017-06-08 20:44:14 | OUT | 0 |
| 7 | 2 | 2017-06-09 11:35:00 | IN | 1 |
| 8 | 2 | 2017-06-09 20:36:06 | OUT | 1 |
现在应该清楚了,我们可以按 employee_id
和 rn_grp
列分组,然后在您的原始问题中使用数据透视查询方法。
请注意,如果员工数据可能具有 IN
值而没有对应的 OUT
值,则此方法可能不起作用。
输出:
此处演示:
您可以使用自联接将 time_in 与 time_out 合并,其中 time_out 在 time_in 之后。然后按 time_in 分组,然后只选择第一个 time_out:
select employee_id, attendance_date, time_in, MIN(time_out) time_out from (
select A.id id, DATE(A.timedata) attendance_date, A.employee_id employee_id, A.timedata time_in, A.in_out, B.timedata time_out
from attendances A
left join attendances B
on A.employee_id = B.employee_id
and A.timedata < B.timedata
and B.in_out = 'OUT'
where A.in_out = 'IN'
) AB
group by employee_id, attendance_date, time_in