在TSQL中,如何计算2个表(登录和退出日志)的持续时间?

时间:2013-12-05 02:37:18

标签: sql-server tsql ssms

我需要从2个表(1个登录日志和1个注销日志)计算持续时间,每个表记录操作的日期时间和与之关联的accountID。目的是查看每个帐户在相应的登录和登录之间登录了多长时间。登出。表格架构如下(因为这是我的第一个帖子,如果格式错误,请道歉。)

UserLogInLog_201307

- DATETIME,datetime,not null

- AccountID,int,not null

UserLogOutLog_201307

- DATETIME,datetime,not null

- AccountID,int,not null

假设时间段为2013-07-17至2013-07-23。

我知道我应该使用DATEDIFF进行计算,但困难的部分是按相应的顺序配对每次登录和注销,并避免因拆分日登录或注销造成的混乱(即如果在2013年登录的帐户 - 07-12&退出2013-07-13)。

我最初的解决方案是使用AccountID& amp;分区。按DATETIME排名作为每一对的“锚”,然后我意识到由于分裂日的混乱而错了。

此外,我只对数据库具有只读权限,因此无法创建新的表/函数等。

有人可以给我一个解决方案吗?非常感谢你提前。

这是我的初始代码(不正确)供您参考:

-- RANK LOGOUT LOG BY LOGIN TIME
WITH cteLOGIN AS
(
    SELECT AccountID
          ,[DATETIME] AS [LOGIN]
          ,RANK() OVER (PARTITION BY AccountID ORDER BY [DATETIME] ASC) AS [xRANK]
        FROM [GameLog].[dbo].[UserLogInLog_201307]
        WHERE DATETIME BETWEEN '2013-07-17' AND '2013-07-23'
)

-- RANK LOGOUT LOG BY LOGOUT TIME
,cteLOGOUT AS
(
    SELECT AccountID
          ,[DATETIME] AS [LOGOUT]
          ,RANK() OVER (PARTITION BY AccountID ORDER BY [DATETIME] ASC) AS [xRANK]
        FROM [GameLog].[dbo].[UserLogOutLog_201307]
        WHERE DATETIME BETWEEN '2013-07-17' AND '2013-07-23'
)

-- COMBINE LOGIN & LOGOUT; MATCH RECORDS BY RANK #      
SELECT A.AccountID
      ,AVG(DATEDIFF(MINUTE,A.LOGIN,B.LOGOUT)) AS AVG_TIME_DURATION
    FROM cteLOGIN A JOIN cteLOGOUT B ON A.AccountID = B.AccountID
    WHERE A.xRANK = B.xRANK
      AND A.LOGIN < B.LOGOUT
    GROUP BY A.AccountID

2 个答案:

答案 0 :(得分:1)

我认为这里最好的方法是使用相关的子查询。

select ul.*, datediff(minute, datetime, logoutTime) as duration
from (select ulil.*,
             (select top 1 ulol.datetime
              from UserLogOutLog_201307 ulol
              where ulil.AccountId = ulol.AccountId and
                    ulol.datetime > ulil.datetime
             ) as logoutTime
      from UserLogInLog_201307 ulil
     ) ul;

然后,您可以过滤登录日期时间。

答案 1 :(得分:0)

我认为最好的方法是组合表格(不用担心,我不会要求你改变架构)。这是一个查询,可以生成表格的视图,其中有单独的开始和结束时间:

;WITH Unioned as
(
    select [AccountID] id, [DATETIME] dt, 'in' thing from UserLogInLog_201307
    union 
    select [AccountID] id, [DATETIME] dt, 'out' thing from UserLogOutLog_201307
)
,Combined as
(
    select id, dt StartDt, LEAD(dt) OVER (PARTITION BY id ORDER BY dt)  EndDt, thing
    from Unioned
)
SELECT * from Combined 
WHERE 1=1
AND thing = 'in' AND EndDt IS NOT NULL /*only use rows where the current action is 'login' and there is a corresponding logout time*/
AND StartDt >= '2013-01-01 00:15' and EndDt <= '2013-01-03'

现在你应该可以使用它来通过AccountID进行分组并获取平均日期值。