2015-12-30 4 views
1

Я пытаюсь вычислить часы, отработанные из базы данных часов времени. Есть несколько проблем с запросом, я придумал, что я не могу понять.MSSQL Расчет времени от времени между отметками времени

1) Если пользователь оленья кожа часы в течение дня он думает пользователь работал до часов. Если пользователь забывает часы из часы в должны быть выброшены из запроса

2) Запрос ОЧЕНЬ медленно. Есть ли лучший способ, который я могу использовать, чтобы ускорить его?

WITH AUXILIERY_TBL AS (
SELECT [First Name],Checktime,ROW_NUMBER() OVER (ORDER BY CheckTime ASC) AS Ordr 
From Clock_Data 
LEFT JOIN Employees ON Employees.[ID Number] = Clock_Data.UserId 
    WHERE Employees.[First Name]='Hogen' AND Year(CheckTime) > YEAR(GetDate()) - 6 
    ) 
SELECT * FROM(
     SELECT 
     A.Ordr Number,a.[First Name],A.Checktime ct ,B.Checktime ct2,(DATEDIFF(MINUTE ,A.Checktime ,B.Checktime)/60) AS Hours 
     FROM AUXILIERY_TBL AS A 
     LEFT JOIN AUXILIERY_TBL AS B 
       ON (A.Ordr=(B.Ordr-1)) 
    )c 
WHERE c.Number % 2 <> 0 

необработанных данных выглядит следующим образом:

HOGEN     2013-10-28 09:30:00 
HOGEN     2013-10-28 13:30:00 
HOGEN     2013-10-28 14:00:00 
HOGEN     2013-10-28 18:00:00 
HOGEN     2013-10-29 09:31:00 
HOGEN     2013-10-29 14:17:00 
HOGEN     2013-10-29 18:00:00 
HOGEN     2013-10-30 09:59:00 
HOGEN     2013-10-30 14:06:00 
HOGEN     2013-10-30 14:37:00 
HOGEN     2013-10-30 18:10:00 

c.f. SqlFiddle

+0

«выборка данные» должны быть предоставлены «за исходную таблицу», т.е. вставляет для dbo.Clock_Data и для dbo.Employees, или вы могли бы установить sqlfiddle, возможно. –

+0

Расчетные (отработанные) часы могут быть чрезвычайно сложными. Будете ли вы учитывать Overtime, Doubletime, штрафы за тайминги в конце, округление вперед/назад до ближайшего 15-минутного интервала и т. Д.? Вы уже столкнулись с ненормальной ситуацией в вопросе №1. Это может быть первый из тысяч. Я работал в компании, которая написала программное обеспечение времени и посещаемости. Бизнес-логика «правил расчета заработной платы» (которая учитывала бы ваш сценарий для Вопроса № 1) была чрезвычайно сложной. Это также не было написано в tsql. Не уверен, что это относится к вам или если это помогает. – DMason

+0

При любых изменениях вы можете обновить Sql-сервер до 'Sql server 2012' –

ответ

1

Что вы на самом деле нужно что-то вроде LAG или LEAD аналитических функций, предусмотренных в SQLServer 2012+, который получает столбец из одних и тех же результатов выберите N строк вверх или вниз, на основании указанного разделения и упорядочения.

В моем решении я просматриваю таблицу Clock_Data, предполагая, что время - время проверки, а затем я имитирую функцию LAG с коррелированным подзапросом, чтобы получить проверку сотрудника на время, основанное на каждом времени проверки. Конечно, не все времена проверяются, поэтому я добавил в подзапрос условие HAVING, чтобы определить, было ли выбрано время проверки, - это нечетная строка за время, доступное до выписки в тот же день. Если да, то верните время, если не верните null, чтобы мы могли пропустить эти строки после.

Смотрите SQL и, пожалуйста, постарайтесь не использовать имена столбцов с пробелами ... по крайней мере, использовать символ подчеркивания:

select 
    ep.[First Name], 
    z.CheckIn, 
    z.CheckTime as CheckOut, 
    DATEDIFF(MINUTE, z.CheckIn, z.CheckTime)/60 AS Hours 
from 
(
    select 
    cd.*, 
    (
     -- simulating a LAG(CheckTime, 1, null) with this subquery 
     select max(CheckTime) 
     from Clock_Data 
     where 1=1 
     -- select only times from the same employee 
     and UserID = cd.UserID 
     -- select only times before the checkout time (cd.CheckTime) 
     and CheckTime < cd.CheckTime 
     -- select only times from the same year/month/day 
     and CheckTime >= convert(date, cd.CheckTime) 
     group by UserID 
     -- as we're selecting the max(CheckTime) before a check out time 
     -- in the same day, we're selecting the immediatelly previous row/time 
     -- but this subquery must select an odd number of rows 
     -- to ensure the max(CheckTime) is a check in time 
     -- since the check in always occurs first, before a check out 
     -- if it's an even number of rows, null is returned 
     having count(*) % 2 = 1 
    ) as checkIn 
    from Clock_Data cd 
) z 
inner join Employees ep on 1=1 
    and ep.[ID Number] = z.UserID 
    -- and ep.[First Name] = 'Hogen' 
where 1=1 
    and z.checkIn is not null 
Смежные вопросы