Mysql 如何将记录选择到单个记录中以确定时差
我有一个第三方计时应用程序,我们用它来跟踪我们员工的移动。它运行在MariaDB上,但它相当混乱(依我看)。前端是基于windows的,所有处理都在那里进行。问题是我想提取一些数据用于实时报告 所有计时活动都保存到一个表中。见下面的示例Mysql 如何将记录选择到单个记录中以确定时差,mysql,mariadb,mariasql,Mysql,Mariadb,Mariasql,我有一个第三方计时应用程序,我们用它来跟踪我们员工的移动。它运行在MariaDB上,但它相当混乱(依我看)。前端是基于windows的,所有处理都在那里进行。问题是我想提取一些数据用于实时报告 所有计时活动都保存到一个表中。见下面的示例 INDX _DATE_ _TIME_ SURNAME WIEGANDID ZKINOUT 51 2018/09/03 5:52:04 Thakadu 000000000000AE 0 198 2
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
这样我就可以计算出每个员工在一段时间内的实际上班时间
我通过分组和案例取得了一些成功,但问题出在夜班工作的员工身上
任何帮助都将不胜感激
---------------------------------更新-------------------------------
好的,非常感谢所有的贡献者。我几乎得到了答案,只是还没有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
目前,我已经修改了代码,只选择了一名员工。我得到的结果几乎是我想要的,除了它似乎将表a的每条记录连接到表b的每条记录?下面是结果样本的图像
我上周刚刚完成了一个应用程序的创建,该应用程序用于监控员工的punchIN和PunchOUT时间,以监控他们的出勤情况,以及他们的休假、半天等,从而进一步分析数据 看到你提供的数据,我会建议是什么让我的分析应用程序非常简单。使用punchIN和PunchOUT的时间戳数据类型,这一步不仅会合并你现有的列,而且会让你的工作没有障碍 使用输入和输出时间,您可以计算“工作时间”(简单的算术!)。您可以添加标志以查看一个人是否在夜间工作(使用BETWEEN函数),等等。 易于使用的简单功能将引领潮流
请让我知道如果你需要任何帮助 正如ArSuKa大师所说,通过重新设计数据库,您当然可以更轻松地实现这一点。但是,让我们看看,我们能否仅凭你所拥有的就得到你的结果。 如果班次已经结束,我们还通过将临时表中的两个时间戳进行差分来计算工作小时数(浮动数)。使用临时日期时间列可以解决员工夜班的问题。无论班次是否在不同的日期结束,计算都是正确的
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
选择COALESCE(a.DATE\u IN,b.DATE\u IN)作为DATE\u IN,
SUBSTR(合并(a.TIME_IN,b.TIME_IN),1,8)作为TIME_IN,
当(b.DATE\u TIME\u OUT>a.DATE\u TIME\u IN)然后合并(a.DATE\u OUT,
b、 DATE_OUT)否则“”以DATE_OUT结束,
案例时间(b.日期时间>a.日期时间)然后
SUBSTR(合并(a.超时,b.超时),1,8)否则“”结束
随着时间的流逝,
合并(a姓,b姓)为姓氏,
合并(a.维根迪德,b.维根迪德)为维根迪德,
案例时间(b.日期时间>a.日期时间)然后
TIMESTAMPDIFF(秒,a.DATE\u TIME\u IN,b.DATE\u TIME\u OUT)/3600 ELSE''结束
当你工作的时候
从(
在中选择“日期”作为“日期”,
_随着时间的流逝,
日期为空,
超时时为空,
姓,
维根迪德,
CONCAT(_DATE_,,,_TIME_)作为中的日期时间
从测试
其中ZKINOUT=0)作为,
(
在中选择NULL作为日期,
空值为时间_IN,
_日期uu为日期u OUT,
_随着时间的流逝,
姓,
维根迪德,
CONCAT(_DATE_,,,_TIME_)作为日期_TIME_OUT
从测试
其中ZKINOUT=1)为b
其中a.WIEGANDID=b.WIEGANDID
工作时间<15小时且工作时间为“
按1、2、3、4排序
这看起来有点复杂,它执行以下操作。
将创建两个临时表a和b。以下是()中的SELECT语句。一个临时表包含登录记录,另一个包含注销记录。相应的“缺失”字段设置为空
然后可以使用WIEGANDID将这些表相互连接起来。COALESCE确保过滤掉空值,并将其替换为包含正确值的其他临时表中的值。检查DATE_TIME_OUT是否大于DATE_TIME_IN可确保DATE_OUT和TIME_OUT在相应工作人员尚未注销时保持为空
我在结果表中添加了一个新列:HOURS_WORKED。它包含作为浮点数的工作小时数。结果集中忽略尚未结束的班次(工作小时数“”)。太多的重复和避免太多的复杂性,我们过滤掉工作时间超过15小时的结果集记录,因为这在现实中不会发生,而且通常两个班次之间有足够的时间,我们不会赶上两个短班次。不是通用解决方案,而是适用于此特定应用程序的解决方案
您可以在CREATEVIEW语句中使用上述语句。然后可以使用视图而不是原始表,这将有助于降低复杂性
下图显示了基于所有样本记录的上述查询结果。
考虑将日期和时间存储为单个实体。这将大大简化问题。如果可以将日期和时间转换为完整的时间戳,那么可以选择“CASE WHEN zkinout=0然后-timestamp ELSE timestamp”并收集这些值的总和。但是,这并不能解释当前活动的班次。我想要个人