mysql - 如何将记录选择为单个记录以确定时间差

标签 mysql mariadb mariasql

我有一个第 3 方计时应用程序,我们用它来跟踪员工的行动。它在 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 取得一些成功,但问题出在夜类员工身上。

如有任何帮助,我们将不胜感激。

--------------------------------更新------------ ------------------

好的,非常感谢所有贡献者。我几乎得到了答案,除了还没有 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 的每条记录?下面是结果示例的图片。

Sample of result set

最佳答案

正如 ArSuKa 大师所说,您当然可以通过重新设计数据库使这一切变得容易得多。但是让我们看看我们是否可以仅凭您所拥有的就得到您的结果。 我们还通过比较临时表中的两个时间戳来计算工作时间( float ),以防轮类已经结束。使用临时 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。它包含作为 float 工作的小时数。结果集中将忽略尚未结束的类次 (HOURS_WORKED <> '')。为了消除重复项并避免过于复杂,我们过滤掉了 HOURS_WORKED > 15 的结果集记录,因为这在现实中不会发生,而且两次轮类之间通常有足够的时间,我们不会 catch 两次短类次。不是通用解决方案,而是适用于此特定应用程序的解决方案。

您可以在 CREATE VIEW 语句中使用上述语句。然后您可以使用 View 而不是原始表,这将有助于降低复杂性。

下图显示了根据您的所有样本记录进行上述查询的结果。 enter image description here

关于mysql - 如何将记录选择为单个记录以确定时间差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52520904/

相关文章:

mysql - 如何设置mysqladmin默认用户和密码?

mariadb - 像跟踪 MongoDB 操作日志一样跟踪 MariaDB 数据库更改

node.js - 错误: Cannot find module '../build/Debug/sqlclient'

mysql - 优化多级 MySQL 子查询(folksonomy 和分类法)

mysql - 从另一个表插入,然后通过 id 链接表

Mysql - 秒差意外结果

MySQL 试图同时使用 INNER JOIN 和 UNION?

mysql - 选择所有行 (700000) 很长时间 - 小时

jpa - 使用 jpa 自动生成字符串非主键值

php - Zabbix浏览时出错: "Configuration file error DB type "MYSQL"is not supported by current setup.”