SQL: сумма временных интервалов одного дня - PullRequest
1 голос
/ 18 июня 2019

Я настраиваю новый SQL-запрос для суммирования записей из таблицы посещаемости сотрудников.Эти записи загружаются с сенсора отпечатков пальцев или RFID и записываются в одну таблицу.Я хочу получить количество часов на рабочем месте.

Все работает нормально, если сотрудник входит и уходит с работы один раз в день.Устройство генерирует 2 записи в таблице, и это не проблема.Легко определить время входа и выхода.

Но я не понимаю, как решить, если человек входит, делает перерыв (покидает рабочее место), и после этого он входит снова до времени выхода.

Предположим, что они всегда являются четными записями (отметки времени прибытия и выхода) на каждом интервале.Кроме того, сотрудник никогда не проверяет в один день и уходит на следующий день.

У меня есть следующий запрос.Помните: при этом получаются только минимальная временная метка (время прибытия) и максимальная временная метка (время выхода).

SELECT Userid, Name, Date, Entrance, Exit, Hours FROM
            (SELECT Userid AS user,
            CONVERT(VARCHAR, CONVERT(TIME, min(Checktime))) AS Entrance,
            CONVERT(VARCHAR, CONVERT(TIME, max(Checktime))) AS Exit,
            CONVERT(VARCHAR, CONVERT(TIME, max(Checktime)-min(CheckTime))) AS Hours,
            CONVERT(VARCHAR, CONVERT(DATE, CheckTime)) AS Fecha,
            COUNT(*) AS Regs,
            SUM(edited) AS edited FROM attendance
            WHERE CONVERT(DATE, CheckTime) < CONVERT(DATE, GETDATE())
            GROUP BY Userid, CONVERT(DATE, CheckTime)) AS Hs
            INNER JOIN Userinfo
            ON Userinfo.Userid = Hs.user
            ORDER BY Date DESC, Name ASC;

Например, если в таблице есть следующие записи:

id  |  Logid   |  Userid  |       CheckTime       |  edited
1   |      10  |       1  |    2019-06-18 8:00:00 |     0
2   |      11  |       1  |   2019-06-18 12:00:00 |     0
3   |      12  |       1  |   2019-06-18 15:00:00 |     0
4   |      13  |       1  |   2019-06-18 17:00:00 |     0
5   |      14  |       2  |    2019-06-18 8:00:00 |     0
6   |      15  |       2  |   2019-06-18 17:00:00 |     0

Что я получаю:

Userid  |  Name     |     Date     |  Entrance  |   Exit   |  Hours  |  edited
     1  |  Gandalf  |  2019-06-18  |    8:00:00 | 17:00:00 | 9:00:00 |      0
     2  |    Frodo  |  2019-06-18  |    8:00:00 | 17:00:00 | 9:00:00 |      0

Что мне нужно:

Userid  |  Name     |     Date     |  Entrance  |   Exit   |  Hours  |  edited
     1  |  Gandalf  |  2019-06-18  |    8:00:00 | 17:00:00 | 6:00:00 |      0
     2  |    Frodo  |  2019-06-18  |    8:00:00 | 17:00:00 | 9:00:00 |      0

Общее время было рассчитано с (12:00:00 - 8:00:00) + (17:00: 00 - 15:00:00).В этом случае столбцы «Вход» и «Выход» вообще не нужны.

У вас есть идея, как мне это решить?Большое спасибо!

Ответы [ 2 ]

2 голосов
/ 18 июня 2019

Предполагается, что у вас есть пара входов / выходов и обработка нескольких перерывов.

SQL DEMO

with cte as (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY [Userid], cast ([CheckTime] as Date) 
                               ORDER BY [CheckTime]) as rn
  FROM Table1 t1
)  
SELECT c1.[Userid], 
       cast (c1.[CheckTime] as Date) as the_day,
       SUM (DATEDIFF (hh, c1.[CheckTime], c2.[CheckTime])) as total_hours
FROM cte c1
JOIN cte c2
  ON c1.rn = c2.rn -1
 AND c1.[Userid] = c2.[Userid]
 AND c1.rn % 2 = 1
GROUP BY c1.[Userid],
         cast (c1.[CheckTime] as Date) ;

ВЫХОД

| Userid |    the_day | total_hours |
|--------|------------|-------------|
|      1 | 2019-06-18 |           6 |
|      2 | 2019-06-18 |           9 |

Примечание:

Общий синтаксис для DATEDIFF :

DATEDIFF(datepart, start_date, end_date)

Просто поймите, что функция DATEDIFF используется для вычисления временного интервала между двумя значениями даты и возврата его в виде целого числа.

Так что, если у вас 08:00 и 09:30 с использованием hh в качестве даты, вы все равно получите 1 час. Может быть, лучше использовать mi и разделить на 60

0 голосов
/ 18 июня 2019

Отлично! Решение Хуана Карлоса прекрасно работает!

Я публикую это, потому что я отредактировал часть его кода в соответствии с первоначальными требованиями к публикации.

Код точно такой же. Только я изменил / добавил несколько строк

with cte as (
  SELECT  *, ROW_NUMBER() OVER (PARTITION BY [Userid], cast ([CheckTime] as Date)
                               ORDER BY [CheckTime]) as rn
  FROM Table1 t1
  WHERE CAST(CheckTime AS DATE) = '2019-06-17'  -- Filter by specific date 
)
SELECT c1.[Userid],
       cast (c1.[CheckTime] as Date) as the_day,
       -- Return time as HH:MM
       CONVERT(VARCHAR, SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/3600) + ':' + right('00' + CONVERT(VARCHAR, CONVERT(FLOAT, (SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/60) - ((SUM (DATEDIFF (SECOND , c1.[CheckTime], c2.[CheckTime]))/3600)*60))),2) as total_time
FROM cte c1
JOIN cte c2
  ON c1.rn = c2.rn -1
 AND c1.[Userid] = c2.[Userid]
 AND c1.rn % 2 = 1
GROUP BY c1.[Userid],
         cast (c1.[CheckTime] as Date);

Этот запрос возвращает:

| Userid |    the_day |  total_time |
|--------|------------|-------------|
|      1 | 2019-06-18 |        6:00 |
|      2 | 2019-06-18 |        9:00 |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...