如何将 SELECT 条记录合并为一条记录以确定 TIME 差异
How to SELECT records into a single record to determine TIME difference
我有一个第三方时钟应用程序,我们用它来跟踪员工的行动。它在 MariaDB 上运行,但它非常混乱(imo)。前端是基于 windows 的,所有处理都在那里进行。问题是我想提取一些数据用于实时报告。
所有计时活动都保存到一个 table。请参阅下面的示例。
INDX _DATE_ _TIME_ SURNAME WIEGANDID ZKINOUT
51 2018/09/03 5:52:04 Thakadu 000000000000AE 0
198 2018/09/03 14:04:29 Thakadu 000000000000AE 1
309 2018/09/03 21:54:06 Mabeo 000000000000BA 0
370 2018/09/04 5:47:20 Thakadu 000000000000AE 0
401 2018/09/04 6:00:09 Mabeo 000000000000BA 1
557 2018/09/04 14:04:57 Thakadu 000000000000AE 1
691 2018/09/04 21:53:33 Mabeo 000000000000BA 0
748 2018/09/05 5:47:20 Thakadu 000000000000AE 0
780 2018/09/05 6:00:34 Mabeo 000000000000BA 1
946 2018/09/05 14:05:32 Thakadu 000000000000AE 1
1089 2018/09/05 21:49:48 Mabeo 000000000000BA 0
1144 2018/09/06 5:50:41 Thakadu 000000000000AE 0
1174 2018/09/06 6:00:16 Mabeo 000000000000BA 1
1328 2018/09/06 14:09:28 Thakadu 000000000000AE 1
1482 2018/09/06 21:50:32 Mabeo 000000000000BA 0
1568 2018/09/07 5:58:48 Thakadu 000000000000AE 0
1555 2018/09/07 6:01:01 Mabeo 000000000000BA 1
1812 2018/09/07 14:05:47 Thakadu 000000000000AE 1
1845 2018/09/07 21:51:31 Mabeo 000000000000BA 0
挑战来自 Mabeo 从 22:00:00 到第二天早上 06:00:00 工作的地方。
另外,有时工作人员由于某种原因没有下班,系统会自动将他们注销,而不记录时间。
我希望看到的结果看起来像这样。
DATE_IN TIME_IN DATE_OUT TIME_OUT SURNAME WIEGANDID
2018/09/03 05:52:04 2018/09/03 14:04:29 Thakadu 000000000000AE
2018/09/03 21:54:06 2018/09/04 06:00:09 Mabeo 000000000000BA
2018/09/04 05:47:20 2018/09/04 14:04:57 Thakadu 000000000000AE
2018/09/04 21:53:33 2018/09/05 06:00:16 Mabeo 000000000000BA
这样我就可以计算出每个员工在一段时间内打卡的实际时间。
我使用 GROUP BY 和 CASE 取得了一些成功,但问题出在夜班员工身上。
如有任何帮助,我们将不胜感激。
--------------------------------更新------------ ------------------
好的,非常感谢所有贡献者。我几乎得到了答案,除了还没有 100%。我已经按照@rf1234 的建议使用了以下代码,谢谢您的回答。
SELECT COALESCE (a.DATE_IN, b.DATE_IN) AS DATE_IN,
SUBSTR(COALESCE (a.TIME_IN, b.TIME_IN), 1, 8) AS TIME_IN,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN COALESCE (a.DATE_OUT,
b.DATE_OUT) ELSE '' END AS DATE_OUT,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
SUBSTR(COALESCE (a.TIME_OUT, b.TIME_OUT), 1, 8) ELSE '' END
AS TIME_OUT,
COALESCE (a.SURNAME, b.SURNAME) AS SURNAME,
COALESCE (a.WIEGANDID, b.WIEGANDID) AS WIEGANDID,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
TIMESTAMPDIFF(SECOND, a.DATE_TIME_IN, b.DATE_TIME_OUT) / 3600 ELSE '' END
AS HOURS_WORKED
FROM (
SELECT _DATE_ AS DATE_IN,
_TIME_ AS TIME_IN,
NULL AS DATE_OUT,
NULL AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_IN
FROM _2018_09
WHERE ZKINOUT = 0 AND SURNAME = 'MABEO'
GROUP BY WIEGANDID, _DATE_ ) AS a,
(
SELECT NULL AS DATE_IN,
NULL AS TIME_IN,
_DATE_ AS DATE_OUT,
_TIME_ AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_OUT
FROM _2018_09
WHERE ZKINOUT = 1 AND SURNAME = 'MABEO'
GROUP BY WIEGANDID, _DATE_) AS b
WHERE a.WIEGANDID = b.WIEGANDID
ORDER BY 1, 2, 3, 4
我已经将代码修改为 select 目前只有一名员工。我得到的结果几乎是我想要的,除了它似乎将 table a 的每条记录加入到 table b 的每条记录?下面是结果示例的图像。
我上周才完成了一个应用程序的创建,用于监控员工的打卡和打卡时间,以监控他们的出勤情况,从而监控他们的休假时间、半天时间等,以进一步分析数据。
看到你提供的数据,我会建议是什么让我的分析应用程序非常simple.Use punchIN 和 PunchOUT 的时间戳数据类型,这一步不仅会合并你现有的列,而且会让你的工作无障碍。
使用 IN 和 OUT 时间,您可以计算 "working hours"(简单的算术!)。您可以添加标志以查看某人是否在夜间工作(使用 BETWEEN 函数)等。
即用型简单功能将引领潮流!
如果您需要任何帮助,请告诉我...!!
正如 ArSuKa 大师所说,您当然可以通过重新设计数据库来简化此过程。但是让我们看看我们是否可以仅凭您所拥有的就得到您的结果。
我们还通过比较临时 table 中的两个时间戳来计算工作时间(浮点数),以防轮班已经结束。使用临时 DATE_TIME 列解决了员工上夜班的问题。无论班次是否在不同的一天结束,计算都是正确的。
SELECT COALESCE (a.DATE_IN, b.DATE_IN) AS DATE_IN,
SUBSTR(COALESCE (a.TIME_IN, b.TIME_IN), 1, 8) AS TIME_IN,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN COALESCE (a.DATE_OUT,
b.DATE_OUT) ELSE '' END AS DATE_OUT,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
SUBSTR(COALESCE (a.TIME_OUT, b.TIME_OUT), 1, 8) ELSE '' END
AS TIME_OUT,
COALESCE (a.SURNAME, b.SURNAME) AS SURNAME,
COALESCE (a.WIEGANDID, b.WIEGANDID) AS WIEGANDID,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
TIMESTAMPDIFF(SECOND, a.DATE_TIME_IN, b.DATE_TIME_OUT) / 3600 ELSE '' END
AS HOURS_WORKED
FROM (
SELECT _DATE_ AS DATE_IN,
_TIME_ AS TIME_IN,
NULL AS DATE_OUT,
NULL AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_IN
FROM test
WHERE ZKINOUT = 0 ) AS a,
(
SELECT NULL AS DATE_IN,
NULL AS TIME_IN,
_DATE_ AS DATE_OUT,
_TIME_ AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_OUT
FROM test
WHERE ZKINOUT = 1 ) AS b
WHERE a.WIEGANDID = b.WIEGANDID
HAVING HOURS_WORKED < 15 AND HOURS_WORKED <> ''
ORDER BY 1, 2, 3, 4
这看起来有点复杂,它做了以下事情。
创建了两个临时 tables a 和 b。这些是 () 中的 SELECT 语句。一个临时 table 包含登录记录,另一个包含注销记录。相应的 "missing" 字段设置为 NULL。
然后这些 table 可以使用 WIEGANDID 相互连接。 COALESCE 确保空值被过滤掉并替换为来自另一个包含正确值的临时 table 的值。检查 DATE_TIME_OUT 是否大于 DATE_TIME_IN 确保 DATE_OUT 和 TIME_OUT 在相应的工作人员尚未注销时保持为空。
我在结果 table 中添加了一个新列:HOURS_WORKED。它包含作为浮点数工作的小时数。结果集中将忽略尚未结束的班次 (HOURS_WORKED <> '')。为了消除重复项并避免过于复杂,我们过滤掉了 HOURS_WORKED > 15 的结果集记录,因为这在现实中不会发生,而且两次轮班之间通常有足够的时间,我们不会赶上两次短班次。不是通用解决方案,而是适用于此特定应用程序的解决方案。
您可以在 CREATE VIEW 语句中使用上述语句。然后您可以使用视图而不是原始视图 table,这将有助于降低复杂性。
下图是根据您的所有样本记录进行上述查询的结果。
我有一个第三方时钟应用程序,我们用它来跟踪员工的行动。它在 MariaDB 上运行,但它非常混乱(imo)。前端是基于 windows 的,所有处理都在那里进行。问题是我想提取一些数据用于实时报告。
所有计时活动都保存到一个 table。请参阅下面的示例。
INDX _DATE_ _TIME_ SURNAME WIEGANDID ZKINOUT
51 2018/09/03 5:52:04 Thakadu 000000000000AE 0
198 2018/09/03 14:04:29 Thakadu 000000000000AE 1
309 2018/09/03 21:54:06 Mabeo 000000000000BA 0
370 2018/09/04 5:47:20 Thakadu 000000000000AE 0
401 2018/09/04 6:00:09 Mabeo 000000000000BA 1
557 2018/09/04 14:04:57 Thakadu 000000000000AE 1
691 2018/09/04 21:53:33 Mabeo 000000000000BA 0
748 2018/09/05 5:47:20 Thakadu 000000000000AE 0
780 2018/09/05 6:00:34 Mabeo 000000000000BA 1
946 2018/09/05 14:05:32 Thakadu 000000000000AE 1
1089 2018/09/05 21:49:48 Mabeo 000000000000BA 0
1144 2018/09/06 5:50:41 Thakadu 000000000000AE 0
1174 2018/09/06 6:00:16 Mabeo 000000000000BA 1
1328 2018/09/06 14:09:28 Thakadu 000000000000AE 1
1482 2018/09/06 21:50:32 Mabeo 000000000000BA 0
1568 2018/09/07 5:58:48 Thakadu 000000000000AE 0
1555 2018/09/07 6:01:01 Mabeo 000000000000BA 1
1812 2018/09/07 14:05:47 Thakadu 000000000000AE 1
1845 2018/09/07 21:51:31 Mabeo 000000000000BA 0
挑战来自 Mabeo 从 22:00:00 到第二天早上 06:00:00 工作的地方。 另外,有时工作人员由于某种原因没有下班,系统会自动将他们注销,而不记录时间。
我希望看到的结果看起来像这样。
DATE_IN TIME_IN DATE_OUT TIME_OUT SURNAME WIEGANDID
2018/09/03 05:52:04 2018/09/03 14:04:29 Thakadu 000000000000AE
2018/09/03 21:54:06 2018/09/04 06:00:09 Mabeo 000000000000BA
2018/09/04 05:47:20 2018/09/04 14:04:57 Thakadu 000000000000AE
2018/09/04 21:53:33 2018/09/05 06:00:16 Mabeo 000000000000BA
这样我就可以计算出每个员工在一段时间内打卡的实际时间。
我使用 GROUP BY 和 CASE 取得了一些成功,但问题出在夜班员工身上。
如有任何帮助,我们将不胜感激。
--------------------------------更新------------ ------------------
好的,非常感谢所有贡献者。我几乎得到了答案,除了还没有 100%。我已经按照@rf1234 的建议使用了以下代码,谢谢您的回答。
SELECT COALESCE (a.DATE_IN, b.DATE_IN) AS DATE_IN,
SUBSTR(COALESCE (a.TIME_IN, b.TIME_IN), 1, 8) AS TIME_IN,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN COALESCE (a.DATE_OUT,
b.DATE_OUT) ELSE '' END AS DATE_OUT,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
SUBSTR(COALESCE (a.TIME_OUT, b.TIME_OUT), 1, 8) ELSE '' END
AS TIME_OUT,
COALESCE (a.SURNAME, b.SURNAME) AS SURNAME,
COALESCE (a.WIEGANDID, b.WIEGANDID) AS WIEGANDID,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
TIMESTAMPDIFF(SECOND, a.DATE_TIME_IN, b.DATE_TIME_OUT) / 3600 ELSE '' END
AS HOURS_WORKED
FROM (
SELECT _DATE_ AS DATE_IN,
_TIME_ AS TIME_IN,
NULL AS DATE_OUT,
NULL AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_IN
FROM _2018_09
WHERE ZKINOUT = 0 AND SURNAME = 'MABEO'
GROUP BY WIEGANDID, _DATE_ ) AS a,
(
SELECT NULL AS DATE_IN,
NULL AS TIME_IN,
_DATE_ AS DATE_OUT,
_TIME_ AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_OUT
FROM _2018_09
WHERE ZKINOUT = 1 AND SURNAME = 'MABEO'
GROUP BY WIEGANDID, _DATE_) AS b
WHERE a.WIEGANDID = b.WIEGANDID
ORDER BY 1, 2, 3, 4
我已经将代码修改为 select 目前只有一名员工。我得到的结果几乎是我想要的,除了它似乎将 table a 的每条记录加入到 table b 的每条记录?下面是结果示例的图像。
我上周才完成了一个应用程序的创建,用于监控员工的打卡和打卡时间,以监控他们的出勤情况,从而监控他们的休假时间、半天时间等,以进一步分析数据。
看到你提供的数据,我会建议是什么让我的分析应用程序非常simple.Use punchIN 和 PunchOUT 的时间戳数据类型,这一步不仅会合并你现有的列,而且会让你的工作无障碍。
使用 IN 和 OUT 时间,您可以计算 "working hours"(简单的算术!)。您可以添加标志以查看某人是否在夜间工作(使用 BETWEEN 函数)等。 即用型简单功能将引领潮流!
如果您需要任何帮助,请告诉我...!!
正如 ArSuKa 大师所说,您当然可以通过重新设计数据库来简化此过程。但是让我们看看我们是否可以仅凭您所拥有的就得到您的结果。 我们还通过比较临时 table 中的两个时间戳来计算工作时间(浮点数),以防轮班已经结束。使用临时 DATE_TIME 列解决了员工上夜班的问题。无论班次是否在不同的一天结束,计算都是正确的。
SELECT COALESCE (a.DATE_IN, b.DATE_IN) AS DATE_IN,
SUBSTR(COALESCE (a.TIME_IN, b.TIME_IN), 1, 8) AS TIME_IN,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN COALESCE (a.DATE_OUT,
b.DATE_OUT) ELSE '' END AS DATE_OUT,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
SUBSTR(COALESCE (a.TIME_OUT, b.TIME_OUT), 1, 8) ELSE '' END
AS TIME_OUT,
COALESCE (a.SURNAME, b.SURNAME) AS SURNAME,
COALESCE (a.WIEGANDID, b.WIEGANDID) AS WIEGANDID,
CASE WHEN ( b.DATE_TIME_OUT > a.DATE_TIME_IN ) THEN
TIMESTAMPDIFF(SECOND, a.DATE_TIME_IN, b.DATE_TIME_OUT) / 3600 ELSE '' END
AS HOURS_WORKED
FROM (
SELECT _DATE_ AS DATE_IN,
_TIME_ AS TIME_IN,
NULL AS DATE_OUT,
NULL AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_IN
FROM test
WHERE ZKINOUT = 0 ) AS a,
(
SELECT NULL AS DATE_IN,
NULL AS TIME_IN,
_DATE_ AS DATE_OUT,
_TIME_ AS TIME_OUT,
SURNAME,
WIEGANDID,
CONCAT( _DATE_, ' ', _TIME_ ) AS DATE_TIME_OUT
FROM test
WHERE ZKINOUT = 1 ) AS b
WHERE a.WIEGANDID = b.WIEGANDID
HAVING HOURS_WORKED < 15 AND HOURS_WORKED <> ''
ORDER BY 1, 2, 3, 4
这看起来有点复杂,它做了以下事情。 创建了两个临时 tables a 和 b。这些是 () 中的 SELECT 语句。一个临时 table 包含登录记录,另一个包含注销记录。相应的 "missing" 字段设置为 NULL。
然后这些 table 可以使用 WIEGANDID 相互连接。 COALESCE 确保空值被过滤掉并替换为来自另一个包含正确值的临时 table 的值。检查 DATE_TIME_OUT 是否大于 DATE_TIME_IN 确保 DATE_OUT 和 TIME_OUT 在相应的工作人员尚未注销时保持为空。
我在结果 table 中添加了一个新列:HOURS_WORKED。它包含作为浮点数工作的小时数。结果集中将忽略尚未结束的班次 (HOURS_WORKED <> '')。为了消除重复项并避免过于复杂,我们过滤掉了 HOURS_WORKED > 15 的结果集记录,因为这在现实中不会发生,而且两次轮班之间通常有足够的时间,我们不会赶上两次短班次。不是通用解决方案,而是适用于此特定应用程序的解决方案。
您可以在 CREATE VIEW 语句中使用上述语句。然后您可以使用视图而不是原始视图 table,这将有助于降低复杂性。
下图是根据您的所有样本记录进行上述查询的结果。