Mysql 具有时差的员工休息时间历史记录
Mysql Employee break time history with time difference
我有带有 inoutmode
标志的员工生物识别日志数据。我正在尝试获取详细的休息时间列表和时差。
inoutmode
4 次突破,5 次闯入。
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '14:00:13', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '16:07:08', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '16:07:18', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '15:44:26', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '16:37:58', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:01:11', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:01:25', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:30:29', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (326, '2019-09-19', '15:58:30', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (326, '2019-09-19', '19:34:09', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '15:44:19', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '15:55:37', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '19:59:38', 4);
这是我的期望输出
| EmpMachineID | attendance_date | break_out | break_in | Diff |
|--------------|-----------------|------------|-----------|-----------|
| 235 | 2019-09-19 | 15:44:26 | | |
| | 2019-09-19 | 16:37:58 | | |
| | 2019-09-19 | | 20:01:11 | |
| | 2019-09-19 | 20:30:29 | 20:01:25 | 29:04 |
| 326 | 2019-09-19 | 19:34:09 | 15:58:30 | 03:35:39 |
我尽力实现了输出。以下是我尝试的查询:
SELECT l2.empmachineid,
l2.shift_date,
l2.attentime,
l2.inoutmode
FROM tbl_downloadentry AS l2
WHERE l2.inoutmode IN ( 5, 4 )
AND l2.shift_date = "2019-09-19"
ORDER BY l2.empmachineid,
l2.shift_date,
l2.attentime ASC
我的MySQL版本=10.3.17-MariaDB-1-log
SELECT l2.EmpMachineID, l2.shift_date, l2.InOutMode,
case when l2.InOutMode=5 then l2.AttenTime END AS BreakOut,
case when l2.InOutMode=4 then l2.AttenTime END AS BreakIn
FROM tbl_downloadentry AS l2
WHERE l2.InOutMode IN (5, 4) AND l2.shift_date="2019-09-19"
ORDER BY l2.EmpMachineID, l2.shift_date, l2.AttenTime ASC
部分我使用案例条件到达了记录,但 4 和 5 inoutmode 应该在单行中以计算时差。任何想法...
如有任何建议,我们将不胜感激。
如果我理解正确的话,你想将“4”条记录与“5”条记录相关联。你的结果集好像和你的样本数据关系不大,所以很难理解。
以下方法将每个 4/5 与最近的一个相关联。它通过分配一个分组来做到这一点,对每个“4”进行向上计数,对每个“5”进行向下计数。
然而,这并不是完整的解决方案,因为连续“4"s and "5”系列可能会有多次起伏。所以,它分配了一个辅助分组,将其分解。
SELECT EmpMachineID, shift_date,
MAX(CASE WHEN InOutMode = 4 THEN AttenTime END),
MAX(CASE WHEN InOutMode = 5 THEN AttenTime END)
FROM (SELECT dl.*,
SUM(InOutMode = group_first_InOutMode) OVER (PARTITION BY dl.EmpMachineID, dl.shift_date, dl.grouping ORDER BY dl.AttenTime) as secondary_grouping
FROM (SELECT dl.*,
FIRST_VALUE(InOutMode) OVER (PARTITION BY dl.EmpMachineID, dl.shift_date, dl.grouping ORDER BY dl.AttenTime) as group_first_InOutMode
FROM (SELECT dl.*,
SUM( CASE WHEN InOutMode = 4 THEN 1 WHEN InOutMode = 5 THEN -1 END) OVER
(PARTITION BY dl.EmpMachineID, dl.shift_date
ORDER BY dl.AttenTime
) -
(CASE WHEN InOutMode = 5 THEN -1 ELSE 0 END) as grouping -- subtract out "5"s on current row
FROM tbl_downloadentry dl
WHERE dl.InOutMode IN (5, 4) AND dl.shift_date = '2019-09-19'
) dl
) dl
) dl
GROUP BY EmpMachineID, shift_date, grouping, secondary_grouping;
Here 是一个 db<>fiddle.
这是一种利用 MariaDB 10.2+ 和 MySQL 8+ 中可用的 LEAD()
and LAG()
Window 函数的方法。
- 当一个特定的行
InOutMode
模式是4
时,这意味着它是break_out
时间。现在,我们使用 LAG()
函数获取该特定 EmpID 的直接 previous 行。排序是根据时间定义的。因此,如果紧邻的前一行的 InOutMode
模式是 5
,这意味着我们有一个相应的 break_in
时间用于此 break_out
时间,否则 null
.
InOutMode
模式为 5
的行遵循类似的过程。这次唯一不同的是我们使用了 LEAD()
函数;因为我们需要立即获取 next 行,并检查它是否是 break_out
。
- 现在,我们只需要将此结果集用作 Derived Table and
DISTINCT
it out (because we will have duplicate rows for every case where there are break_in and break_out together). Also, in the outer query we can calculate the time difference using TimeDiff()
功能。
为了演示目的,为 EmpID = 235
完成了以下查询:
SELECT
DISTINCT
dt.*,
TIMEDIFF(dt.break_out, dt.break_in) AS diff
FROM
(
SELECT
EmpMachineID,
shift_date,
CASE InOutMode
WHEN 4 THEN AttenTime -- this is break_out row
WHEN 5 THEN -- this is break_in row, find the break_out if exists
CASE
WHEN LEAD(InOutMode) OVER w = 4
THEN LEAD(AttenTime) OVER w
END
END AS break_out,
CASE InOutMode
WHEN 5 THEN AttenTime -- this is break_in row
WHEN 4 THEN -- this is break_out row, find the break_in if exists
CASE
WHEN LAG(InOutMode) OVER w = 5
THEN LAG(AttenTime) OVER w
END
END AS break_in
FROM tbl_downloadentry
WHERE EmpMachineID = 235
AND InOutMode IN (4,5)
AND shift_date = '2019-09-19'
WINDOW w AS (PARTITION BY EmpMachineID
ORDER BY AttenTime ASC)
) AS dt;
结果
| EmpMachineID | shift_date | break_out | break_in | diff |
| ------------ | ---------- | --------- | -------- | -------- |
| 235 | 2019-09-19 | 15:44:26 | | |
| 235 | 2019-09-19 | 16:37:58 | | |
| 235 | 2019-09-19 | | 20:01:11 | |
| 235 | 2019-09-19 | 20:30:29 | 20:01:25 | 00:29:04 |
我有带有 inoutmode
标志的员工生物识别日志数据。我正在尝试获取详细的休息时间列表和时差。
inoutmode
4 次突破,5 次闯入。
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '14:00:13', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '16:07:08', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (105, '2019-09-19', '16:07:18', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '15:44:26', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '16:37:58', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:01:11', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:01:25', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (235, '2019-09-19', '20:30:29', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (326, '2019-09-19', '15:58:30', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (326, '2019-09-19', '19:34:09', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '15:44:19', 5);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '15:55:37', 4);
INSERT INTO `tbl_downloadentry` (`EmpMachineID`, `shift_date`, `AttenTime`, `InOutMode`) VALUES (327, '2019-09-19', '19:59:38', 4);
这是我的期望输出
| EmpMachineID | attendance_date | break_out | break_in | Diff |
|--------------|-----------------|------------|-----------|-----------|
| 235 | 2019-09-19 | 15:44:26 | | |
| | 2019-09-19 | 16:37:58 | | |
| | 2019-09-19 | | 20:01:11 | |
| | 2019-09-19 | 20:30:29 | 20:01:25 | 29:04 |
| 326 | 2019-09-19 | 19:34:09 | 15:58:30 | 03:35:39 |
我尽力实现了输出。以下是我尝试的查询:
SELECT l2.empmachineid,
l2.shift_date,
l2.attentime,
l2.inoutmode
FROM tbl_downloadentry AS l2
WHERE l2.inoutmode IN ( 5, 4 )
AND l2.shift_date = "2019-09-19"
ORDER BY l2.empmachineid,
l2.shift_date,
l2.attentime ASC
我的MySQL版本=10.3.17-MariaDB-1-log
SELECT l2.EmpMachineID, l2.shift_date, l2.InOutMode,
case when l2.InOutMode=5 then l2.AttenTime END AS BreakOut,
case when l2.InOutMode=4 then l2.AttenTime END AS BreakIn
FROM tbl_downloadentry AS l2
WHERE l2.InOutMode IN (5, 4) AND l2.shift_date="2019-09-19"
ORDER BY l2.EmpMachineID, l2.shift_date, l2.AttenTime ASC
部分我使用案例条件到达了记录,但 4 和 5 inoutmode 应该在单行中以计算时差。任何想法...
如有任何建议,我们将不胜感激。
如果我理解正确的话,你想将“4”条记录与“5”条记录相关联。你的结果集好像和你的样本数据关系不大,所以很难理解。
以下方法将每个 4/5 与最近的一个相关联。它通过分配一个分组来做到这一点,对每个“4”进行向上计数,对每个“5”进行向下计数。
然而,这并不是完整的解决方案,因为连续“4"s and "5”系列可能会有多次起伏。所以,它分配了一个辅助分组,将其分解。
SELECT EmpMachineID, shift_date,
MAX(CASE WHEN InOutMode = 4 THEN AttenTime END),
MAX(CASE WHEN InOutMode = 5 THEN AttenTime END)
FROM (SELECT dl.*,
SUM(InOutMode = group_first_InOutMode) OVER (PARTITION BY dl.EmpMachineID, dl.shift_date, dl.grouping ORDER BY dl.AttenTime) as secondary_grouping
FROM (SELECT dl.*,
FIRST_VALUE(InOutMode) OVER (PARTITION BY dl.EmpMachineID, dl.shift_date, dl.grouping ORDER BY dl.AttenTime) as group_first_InOutMode
FROM (SELECT dl.*,
SUM( CASE WHEN InOutMode = 4 THEN 1 WHEN InOutMode = 5 THEN -1 END) OVER
(PARTITION BY dl.EmpMachineID, dl.shift_date
ORDER BY dl.AttenTime
) -
(CASE WHEN InOutMode = 5 THEN -1 ELSE 0 END) as grouping -- subtract out "5"s on current row
FROM tbl_downloadentry dl
WHERE dl.InOutMode IN (5, 4) AND dl.shift_date = '2019-09-19'
) dl
) dl
) dl
GROUP BY EmpMachineID, shift_date, grouping, secondary_grouping;
Here 是一个 db<>fiddle.
这是一种利用 MariaDB 10.2+ 和 MySQL 8+ 中可用的 LEAD()
and LAG()
Window 函数的方法。
- 当一个特定的行
InOutMode
模式是4
时,这意味着它是break_out
时间。现在,我们使用LAG()
函数获取该特定 EmpID 的直接 previous 行。排序是根据时间定义的。因此,如果紧邻的前一行的InOutMode
模式是5
,这意味着我们有一个相应的break_in
时间用于此break_out
时间,否则null
. InOutMode
模式为5
的行遵循类似的过程。这次唯一不同的是我们使用了LEAD()
函数;因为我们需要立即获取 next 行,并检查它是否是break_out
。- 现在,我们只需要将此结果集用作 Derived Table and
DISTINCT
it out (because we will have duplicate rows for every case where there are break_in and break_out together). Also, in the outer query we can calculate the time difference usingTimeDiff()
功能。
为了演示目的,为 EmpID = 235
完成了以下查询:
SELECT
DISTINCT
dt.*,
TIMEDIFF(dt.break_out, dt.break_in) AS diff
FROM
(
SELECT
EmpMachineID,
shift_date,
CASE InOutMode
WHEN 4 THEN AttenTime -- this is break_out row
WHEN 5 THEN -- this is break_in row, find the break_out if exists
CASE
WHEN LEAD(InOutMode) OVER w = 4
THEN LEAD(AttenTime) OVER w
END
END AS break_out,
CASE InOutMode
WHEN 5 THEN AttenTime -- this is break_in row
WHEN 4 THEN -- this is break_out row, find the break_in if exists
CASE
WHEN LAG(InOutMode) OVER w = 5
THEN LAG(AttenTime) OVER w
END
END AS break_in
FROM tbl_downloadentry
WHERE EmpMachineID = 235
AND InOutMode IN (4,5)
AND shift_date = '2019-09-19'
WINDOW w AS (PARTITION BY EmpMachineID
ORDER BY AttenTime ASC)
) AS dt;
结果
| EmpMachineID | shift_date | break_out | break_in | diff |
| ------------ | ---------- | --------- | -------- | -------- |
| 235 | 2019-09-19 | 15:44:26 | | |
| 235 | 2019-09-19 | 16:37:58 | | |
| 235 | 2019-09-19 | | 20:01:11 | |
| 235 | 2019-09-19 | 20:30:29 | 20:01:25 | 00:29:04 |