我有一个第三方时钟应用程序,我们用它来跟踪我们员工的动作。它运行在MariaDB上,但它非常混乱(imo)。前端是基于窗口的,所有处理都在那里进行。问题是我想提取一些实时报告数据。
所有计时活动都保存到一个表中。见下面的示例。
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取得了一些成功,但问题在于员工工作夜班。
任何帮助,将不胜感激。
--------------------------------- UPDATE ---------------- ---------------
好的,非常感谢所有贡献的人。我几乎得到了答案,除了那里还没有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的每个记录?下面是结果样本的图像。
正如ArSuKa大师所说,通过重新设计数据库,你当然可以轻松实现这一目标。但是,让我们看看我们是否可以用你拥有的东西来获得你的结果。我们还通过在临时表中区分两个时间戳来计算班次已经结束的工作小时数(浮点数)。使用临时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
这看起来有点复杂,它执行以下操作。创建两个临时表a和b。这些是()中的SELECT语句。一个临时表包含登录记录,另一个临时表包含注销记录。相应的“缺失”字段设置为NULL。
然后可以使用WIEGANDID将这些表相互连接起来。 COALESCE确保过滤掉空值,并替换为包含正确值的其他临时表中的值。检查DATE_TIME_OUT是否大于DATE_TIME_IN,确保如果相应的工作人员尚未注销,则DATE_OUT和TIME_OUT保持为空。
我在结果表中添加了一个新列:HOURS_WORKED。它包含作为浮点数的小时数。在结果集中忽略尚未结束的移位(HOURS_WORKED <>'')。为了消除重复并避免过多的复杂性,我们过滤掉了HOURS_WORKED> 15的结果集记录,因为实际上并没有这种情况发生,并且在两个班次之间通常有足够的时间我们没有捕获两个短班。不是一般解决方案,而是适用于此特定应用的解决方案。
您可以在CREATE VIEW语句中使用上述语句。然后,您可以使用视图而不是原始表,这将有助于降低复杂性。
我上周才创建了一个应用程序,用于监控我的员工的punchIN和PunchOUT时间,以监控他们的出勤情况,从而将他们的假期,半天等用于进一步分析数据。
看到您提供的数据,我建议使我的分析应用程序非常简单。使用punchIN和PunchOUT的Timestamp数据类型,此步骤不仅会合并您现有的列,还会使您的工作无障碍。
使用IN和OUT时间,您可以计算“工作时间”(简单算术!)。您可以添加标记以查看某人是否在夜间工作(使用BETWEEN功能)等。即用型简单功能将带路!
如果您需要任何帮助,请告诉我...... !!