我有一个包含以下示例输出的表格。
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。原始数据中的第三和第四行。 2.分钟数小时是小时计算中的小时数。
我需要tsql查询的帮助才能获得这些结果。
我当前的代码导致了许多其他问题 - 因为每次都必须在临时表中重新计算。
答案 0 :(得分: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
答案 1 :(得分: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
答案 2 :(得分:0)
这个插入可以用SELECT查询改变吗?
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')