Оператор выбора SQL для времени и посещаемости за месяц - PullRequest
0 голосов
/ 26 января 2019

Кто-нибудь может помочь с этим, пожалуйста?Наша система посещаемости генерирует следующие данные:

Empid    Department  Timestamp                  Read_ID
3221      IT          2017-01-29 11:12:00.000    1
5565      IT          2017-01-29 12:28:06.000    1
5565      IT          2017-01-29 12:28:07.000    1
3221      IT          2017-01-29 13:12:00.000    2
5565      IT          2017-01-29 13:28:06.000    2
3221      IT          2017-01-30 07:42:15.000    1
3221      IT          2017-01-30 16:16:15.000    2
3221      IT          2017-01-31 09:05:00.000    1
3221      IT          2017-01-31 11:05:00.000    2
3221      IT          2017-01-31 13:20:00.000    1
3221      IT          2017-01-31 16:10:00.000    2

Где значение Read_ID:

  • 1 = вход
  • 2 = выход

Я ищу SQL-запрос для запуска на MS SQL 2014, который суммирует время посещаемости для каждого сотрудника ежемесячно, например

Empid   Department  Year    Month   TotalHours
3221    IT          2017    1       15:24
5565    IT          2017    1       01:00

Ответы [ 2 ]

0 голосов
/ 26 января 2019

Этот запрос должен дать вам нужный вам результат. Он работает, выбирая каждую запись и соединяя ее со следующим выходом того же сотрудника (записи без дальнейших выходов игнорируются): это дает нам продолжительность смены сотрудника. Затем результаты агрегируются, и длительности смены суммируются в каждой группе.

SELECT
    t1.empid, 
    t1.department, 
    YEAR(t1.timestamp) Year,
    MONTH(t1.timestamp) Month,
    CONVERT(
        varchar(12), 
        DATEADD(minute, SUM(DATEDIFF(minute, t1.timestamp, t2.timestamp)), 0), 
        114
    ) TotalHours
FROM
    mytable t1
    INNER JOIN mytable t2 
        ON  t1.empid = t2.empid
        AND t2.read_id = 2
        AND t2.timestamp = (
            SELECT MIN(timestamp) 
            FROM mytable 
            WHERE 
                read_id = 2 
                AND empid = t2.empid 
                AND timestamp > t1.timestamp
        )
WHERE 
    t1.read_id = 1 
GROUP BY t1.empid, t1.department, YEAR(t1.timestamp), MONTH(t1.timestamp)
ORDER BY  1, 2, 3, 4

Возвращает:

 empid | department | Year | Month | TotalHours  
 ----: | :--------- | ---: | ----: | :-----------
  3221 | IT         | 2017 |     1 | 15:24:00:000
  5565 | IT         | 2017 |     1 | 02:00:00:000

Демонстрация DB Fiddle на SQL Server 2014


Однако существует крайний случай, когда сотрудник входит дважды, а затем существует (это происходит в ваших данных, когда сотрудник 5565 входит в 29/01/2017 12:28:06 и в 29/01/2017 12:28:07, а затем выходы на 29/01/2017 13:28:06. Приведенный выше запрос учитывает две перекрывающиеся записи и сопоставляет их с одним и тем же выходом, в результате чего этот час работы учитывается дважды.

Хотя это соответствует вашим ожидаемым результатам, это то, что вы действительно хотите? Вот альтернативный запрос, который, если происходит несколько последовательных записей одного и того же сотрудника, учитывает только последний:

SELECT
    t1.empid, 
    t1.department, 
    YEAR(t1.timestamp) Year,
    MONTH(t1.timestamp) Month,
    CONVERT(
        varchar(12), 
        DATEADD(minute, SUM(DATEDIFF(minute, t1.timestamp, t2.timestamp)), 0), 
        114
    ) TotalHours
FROM
    mytable t1
    INNER JOIN mytable t2 
        ON  t1.empid = t2.empid
        AND t2.read_id = 2
        AND t2.timestamp = (
            SELECT MIN(timestamp) 
            FROM mytable 
            WHERE 
                read_id = 2 
                AND empid = t2.empid 
                AND timestamp > t1.timestamp
        )
WHERE 
    t1.read_id = 1 
    AND NOT EXISTS (
        SELECT 1 
        FROM mytable 
        WHERE 
            read_id = 1 
            AND empid = t1.empid 
            AND timestamp > t1.timestamp 
            AND timestamp < t2.timestamp
    ) 
GROUP BY t1.empid, t1.department, YEAR(t1.timestamp), MONTH(t1.timestamp)
ORDER BY  1, 2, 3, 4

Возвращает:

 empid | department | Year | Month | TotalHours  
 ----: | :--------- | ---: | ----: | :-----------
  3221 | IT         | 2017 |     1 | 15:24:00:000
  5565 | IT         | 2017 |     1 | 01:00:00:000

Скрипка БД

0 голосов
/ 26 января 2019

Попробуйте это.Я не был уверен, какой формат времени удовлетворит вашу систему, поэтому я поставил оба:

SELECT * INTO #Tbl3 FROM (VALUES
(3221,'IT','2017-01-29 11:12:00.000',1),
(5565,'IT','2017-01-29 12:28:06.000',1),
(5565,'IT','2017-01-29 12:28:07.000',1),
(3221,'IT','2017-01-29 13:12:00.000',2),
(5565,'IT','2017-01-29 13:28:06.000',2),
(3221,'IT','2017-01-30 07:42:15.000',1),
(3221,'IT','2017-01-30 16:16:15.000',2),
(3221,'IT','2017-01-31 09:05:00.000',1),
(3221,'IT','2017-01-31 11:05:00.000',2),
(3221,'IT','2017-01-31 13:20:00.000',1),
(3221,'IT','2017-01-31 16:10:00.000',2))
x (Empid,Department,Timestamp,Read_ID)

;With cte as (
    SELECT t1.Empid, t1.Department
        , [Year] = Year(t1.Timestamp)
        , [Month] = Month(t1.Timestamp)
        , Seconds = SUM(DATEDIFF(second, t1.Timestamp, t2.Timestamp))
    FROM #Tbl3 as t1
    OUTER APPLY (
        SELECT Timestamp = MIN(t.Timestamp) 
        FROM #Tbl3 as t
        WHERE t.Department = t1.Department and t.Empid = t1.Empid
            and t.Timestamp > t1.Timestamp and t.Read_ID = 2
    ) as t2
    WHERE t1.Read_ID = 1
    GROUP BY t1.Empid, t1.Department, Year(t1.Timestamp), Month(t1.Timestamp))
SELECT *, TotalHours = Seconds / 3600., TotalTime =
    RIGHT('0'+CAST(Seconds / 3600 as VARCHAR),2) + ':' +
    RIGHT('0'+CAST((Seconds % 3600) / 60 as VARCHAR),2) + ':' +
    RIGHT('0'+CAST(Seconds % 60 as VARCHAR),2)
FROM cte;
...