Как выбрать записи в одной записи, чтобы определить разницу во времени - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть стороннее приложение для синхронизации, которое мы используем для отслеживания перемещений наших сотрудников.Он работает на MariaDB, но он довольно грязный (IMO).Внешний интерфейс основан на Windows, и вся обработка происходит там.Проблема в том, что я хотел бы извлечь некоторые данные для отчетов в реальном времени.

Все операции синхронизации сохраняются в одной таблице.См. Пример ниже.

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

Задача возникает там, где Мабео работает с 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

Таким образом, я могу определить фактическое время, за которое каждая emply была синхронизирована в течение определенного периода времени.

Мне удалось добиться некоторого успеха, используя 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

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018

Как говорит мастер 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.Тогда вы могли бы работать с представлением вместо исходной таблицы, что помогло бы уменьшить сложность.

На рисунке ниже показан результат запроса выше, основанный на всех ваших образцах записей.enter image description here

0 голосов
/ 26 сентября 2018

Я закончил создание приложения только на прошлой неделе, чтобы отслеживать время punchIN и PunchOUT моих сотрудников, чтобы отслеживать их посещаемость и, следовательно, занятость, полдня и т. Д. Для дальнейшего анализа данных.

Просмотр предоставленных вами данныхЯ хотел бы предложить то, что сделало мое аналитическое приложение очень простым. Используйте типы данных Timestamp для punchIN и PunchOUT, этот шаг не только объединит ваши существующие столбцы, но и освободит ваши рабочие препятствия.

Используя время IN и OUT, выМожно рассчитать «рабочее время» (простая арифметика!). Вы можете добавить флаги, чтобы увидеть, работал ли человек ночью (используя функцию МЕЖДУ) и т. д. и т. д. Готовые к использованию простые функции будут впереди!

Пожалуйста, дайте мне знать, если вам нужна ЛЮБАЯ помощь ... !!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...