2012-08-03 68 views
1

我在SQL Server 2012中,跟踪登录和退出时间,像这样的表:(1型是登录,2型是注销)获取时间跨度在同一列

UserId Type InsertDate 
2134  1  20120803 06:32:02.230 
2134  1  20120803 10:12:24.350 
2134  2  20120803 10:29:21.550 
2134  2  20120803 14:10:34.220 
5915  1  20120802 14:57:57.453 
5915  2  20120802 16:59:00.477 

我想查询此表 - 显示与计算的时间跨度用户标识的每个登录/注销对秒的分组名单,所以我最终的东西,如:

UserID Duration 
2134  1017 
5915  7263 

UPDATE:对于单个用户可以有多组登录/注销对,并且可能会有没有相应注销的登录。我想忽略没有相应值的登录或注销。

+2

如果什么用户有两对条目?如果缺少类型1或类型2条目,该怎么办? – 2012-08-03 14:47:24

+3

是否有任何边缘案例需要考虑?如果所有这些行都是针对同一个用户的(这是可能的?),会有相同的结果(具有相同的用户标识)还是单行 - 如果是单行,涵盖最大期限?可以有多个'1'只有一个'2',反之亦然?根据你的简单例子写一个查询很简单,但我很好奇它与真实数据有多接近。 – 2012-08-03 14:49:03

+0

我建议为其中一个用户添加一个额外的登录/注销,并且可能仅添加一个仅具有登录权限的用户以及仅具有注销的用户,并更新所需的输出,以便处理边缘案例的期望很明确。 – 2012-08-03 15:57:06

回答

6

现在,SQL Server 2012使自联接和聚集有点不必要。该解决方案可处理同一用户的多次登录。

DECLARE @t TABLE(UserID INT, [Type] TINYINT, InsertDate DATETIME); 

INSERT @t VALUES 
(2134,1,'20120803 10:12:24.350'), 
(2134,2,'20120803 10:29:21.550'), 
(2134,1,'20120803 11:22:24.350'), 
(2134,2,'20120803 11:47:21.550'), 
(5915,1,'20120802 14:57:57.453'), 
(5915,2,'20120802 16:59:00.477'); 

;WITH x AS (
    SELECT UserID, [Type], InsertDate, Prev = LAG(InsertDate, 1) OVER 
    (PARTITION BY UserID ORDER BY InsertDate) FROM @t 
) 
SELECT UserID, DATEDIFF(SECOND, Prev, InsertDate) FROM x WHERE [Type] = 2; 

-- or if you want cumulative time per user even if there are multiple login events: 

;WITH x AS (
    SELECT UserID, [Type], InsertDate, Prev = LAG(InsertDate, 1) OVER 
    (PARTITION BY UserID ORDER BY InsertDate) FROM @t 
) 
SELECT UserID, SUM(DATEDIFF(SECOND, Prev, InsertDate)) 
    FROM x WHERE [Type] = 2 GROUP BY UserID; 

在以前的版本中,你可以使用更复杂的:

;WITH x AS 
(
    SELECT UserID, [Type], InsertDate, 
    rn = ROW_NUMBER() OVER (PARTITION BY UserID ORDER BY InsertDate) 
    FROM @t 
) 
SELECT x.UserID, DATEDIFF(SECOND, x.InsertDate, y.InsertDate) 
    FROM x INNER JOIN x AS y 
    ON x.UserID = y.UserID 
    AND x.rn = y.rn - 1 
    WHERE x.Type = 1 
    AND y.Type = 2; 
+3

今天在sql server 2012中学习了一个新函数(Lag)。很好的答案! – praveen 2012-08-03 15:07:55

+0

太棒了 - 这个伎俩。还了解了滞后(和潜在客户) - 非常全面的答案 – 2012-08-03 15:47:54

+0

@ChrisB乐于提供帮助。 MIN/MAX查询当然要简单得多,但它们只有在每个用户只有一个登录/注销对的情况下才能工作。我假设问题中的示例数据被大大简化,并且缺少多种类型的边缘案例。 – 2012-08-03 15:49:07

0

尝试

select datediff(s, min(InsertDate), max(InsertDate)) as diff 
from your_table 
group by UserId 
+0

这假定每个用户在表中只有一对条目。 – 2012-08-03 14:52:40

0

如果只有一个登录和注销;

select UserId, DATEDIFF(second,Min(InsertDate),Max(InsertDate)) as Duration, 
from Table1 
Group By UserId 
+1

此答案与@ juergend的相同(除了将UserId列添加到输出)。 – 2012-08-03 14:54:30

+0

是的,我没有收到通知,写我的答案。 – saj 2012-08-03 14:57:40