I have a table with the below sample output.
UserID Checktime CheckStatus
3175 2013-12-22 07:02:10.000 I
3175 2013-12-22 13:01:01.000
I took Devart's code and improved it. What I do is I use OUTER APPLY to grab the next row for each "IN" status. I then sort out the bad rows in the where clause. If there are two "IN" in a row, then it grabs the later one.
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'
Results:
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