2014-01-02 6 views
3

У меня есть таблица с приведенным ниже образцом.Рассчитать разницу во времени для посещения

UserID Checktime    CheckStatus 
3175 2013-12-22 07:02:10.000  I 
3175 2013-12-22 13:01:01.000  O 
3175 2013-12-22 13:49:54.000  I 
3175 2013-12-22 13:49:55.000  I 
3175 2013-12-22 15:58:42.000  O 
3175 2013-12-23 06:02:58.000  I 
3175 2013-12-23 14:00:29.000  O 
3175 2013-12-24 05:17:09.000  I 
3175 2013-12-24 12:34:25.000  O 
3175 2013-12-24 12:34:26.000  O 

Я хочу построить запрос для достижения ниже результатов:

UserID Date  CheckIn CheckOut Hours 
3175 2013-12-22 07:02:10 13:01:0 5.98 
3175 2013-12-22 13:49:54 15:58:42 2.15 

Примечание: 1. Дубликат IN является ignored.Third и четвертая строки в исходных данных. 2. Минуты в десятичной точке соответствуют часу в расчете часов.

Мне нужна помощь в запросе tsql для получения этих результатов.

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

+0

Какая версия SQL Server вы используете? –

+0

Mike спасибо за ваш ответ - я использую sql server 2005 – user3153067

+0

Что вы хотите, если in/out перекрывает границу дня? Очевидно, что время ожидания не будет иметь одинаковую дату (поэтому для столбцов проверки/проверки результатов может понадобиться дата). Как насчет ситуаций с только временем проверки? Только время проверки? Когда есть повторные проверки? –

ответ

6

Попробуйте один -

DECLARE @temp TABLE 
(
    UserID INT, 
    Checktime DATETIME, 
    CheckStatus CHAR(1) 
) 

INSERT INTO @temp (UserID, Checktime, CheckStatus) 
VALUES 
    (3175, '20131222 07:02:10.000', 'I'), 
    (3175, '20131222 13:01:01.000', 'O'), 
    (3175, '20131222 13:49:54.000', 'I'), 
    (3175, '20131222 13:49:55.000', 'I'), 
    (3175, '20131222 15:58:42.000', 'O'), 
    (3175, '20131223 06:02:58.000', 'I'), 
    (3175, '20131223 14:00:29.000', 'O'), 
    (3175, '20131224 05:17:09.000', 'I'), 
    (3175, '20131224 12:34:25.000', 'O'), 
    (3175, '20131224 12:34:26.000', 'O') 

SELECT 
     t.UserID 
    , [Date] = DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn)) 
    , CheckIn = CONVERT(VARCHAR(10), t.CheckIn, 108) 
    , CheckOut = CONVERT(VARCHAR(10), t.CheckOut, 108) 
    , [Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut)/60. AS DECIMAL(10,2)) 
FROM (
    SELECT 
      t.UserID 
     , CheckIn = t.Checktime 
     , CheckOut = r.Checktime 
     , RowNum = ROW_NUMBER() OVER (PARTITION BY t.UserID, r.Checktime ORDER BY 1/0) 
    FROM @temp t 
    OUTER APPLY (
     SELECT TOP 1 * 
     FROM @temp t2 
     WHERE t2.UserID = t.UserID 
      AND t2.Checktime > t.Checktime 
      AND DATEADD(dd, 0, DATEDIFF(dd, 0, t.Checktime)) = DATEADD(dd, 0, DATEDIFF(dd, 0, t2.Checktime)) 
      AND t2.CheckStatus = 'O' 
     ORDER BY t2.Checktime 
    ) r 
    WHERE t.CheckStatus = 'I' 
) t 
WHERE t.RowNum = 1 

выход -

UserID  Date     CheckIn CheckOut Hours 
----------- ----------------------- ---------- ---------- -------- 
3175  2013-12-22 00:00:00.000 07:02:10 13:01:01 5.98 
3175  2013-12-22 00:00:00.000 13:49:54 15:58:42 2.15 
3175  2013-12-23 00:00:00.000 06:02:58 14:00:29 7.97 
3175  2013-12-24 00:00:00.000 05:17:09 12:34:25 7.28 
+0

Нам нужны разные записи? пожалуйста, объясните выше код. – Naeem

+0

Требуется ли здесь подзапрос CROSS APPLY? Возможно, это не будет гарантировано в правильном порядке в таблице. – Spikeh

+0

@Spikeh, вы правы. Благодарю. – Devart

0

Я взял код DevArt и усовершенствовал ее. Что я делаю, я использую OUTER APPLY, чтобы захватить следующую строку для каждого статуса «IN». Затем я разбираю плохие строки в разделе where. Если есть два «IN» подряд, то он захватывает более поздний.

DECLARE @temp TABLE 
(
    UserID INT, 
    Checktime DATETIME, 
    CheckStatus CHAR(1) 
) 

INSERT INTO @temp (UserID, Checktime, CheckStatus) 
VALUES 
    (3175, '20131222 07:02:10.000', 'I'), 
    (3175, '20131222 13:01:01.000', 'O'), 
    (3175, '20131222 13:49:54.000', 'I'), 
    (3175, '20131222 13:49:55.000', 'I'), 
    (3175, '20131222 15:58:42.000', 'O'), 
    (3175, '20131223 06:02:58.000', 'I'), 
    (3175, '20131223 14:00:29.000', 'O'), 
    (3175, '20131224 05:17:09.000', 'I'), 
    (3175, '20131224 12:34:25.000', 'O'), 
    (3175, '20131224 12:34:26.000', 'O') 

SELECT UserID, 
     CAST(I.CheckTime AS DATE) AS [Date], 
     CONVERT(VARCHAR(10), I.CheckTime, 108) AS CheckIn, 
     CONVERT(VARCHAR(10), O.CheckTime, 108) AS CheckOut, 
     CAST(DATEDIFF(MINUTE,I.checkTime,O.CheckTime)/60.0 AS DECIMAL(18,2)) [Hours] 
FROM @temp I 
OUTER APPLY (
       SELECT TOP 1 Checktime, 
           CheckStatus 
       FROM @temp t 
       WHERE  t.UserID = I.UserID 
         AND t.Checktime > I.Checktime 
       ORDER BY t.Checktime 
      ) O 
WHERE I.CheckStatus = 'I' 
AND O.CheckStatus = 'O' 

Результаты:

UserID  Date  CheckIn CheckOut Hours 
----------- ---------- ---------- ---------- ----- 
3175  2013-12-22 07:02:10 13:01:01 5.98 
3175  2013-12-22 13:49:55 15:58:42 2.15 
3175  2013-12-23 06:02:58 14:00:29 7.97 
3175  2013-12-24 05:17:09 12:34:25 7.28 
Смежные вопросы