计算用户唯一的开始结束时间集

时间:2012-02-21 07:45:34

标签: sql-server-2005

我需要协助处理以下情况。

此表位于SQL Server 2005上。如果您觉得2008年的某些功能会有所帮助,我们也可以访问SQL Server 2008。我可以做到这一点作为最后的选择。 :)

我已登录系统的100多个用户的登出时间。他们可以同时登录不同的频道。

我需要端到端登录注销时间而不管频道

我猜这可以通过存储过程来完成。但如果它没有达到性能,我可以接受任何其他选择。

AgentResults2以下是我的基本表。

AgentOutcome表是我希望输出看起来的样子。

基表的一个例子

FUser_id           FLoginDt                 FLogoutDt
30001              2012-02-17 12:32:15.473  2012-02-17 14:15:36.547
30001              2012-02-17 12:49:48.177  2012-02-17 14:10:01.097
30001              2012-02-17 14:30:49.293  2012-02-17 15:41:02.387

此用户登录到12.32的频道,直到14:15,在此期间他还登录到另一个频道12:49并一直待到14:10。并于14:30至15:41重新登录。我想从这里得到两行

FUser_id           FLoginDt                 FLogoutDt
30001              2012-02-17 12:32:15.473  2012-02-17 14:15:36.547
30001              2012-02-17 14:30:49.293  2012-02-17 15:41:02.387

当你查看用户39395

时会变得复杂
SET DATEFORMAT DMY

IF OBJECT_ID('#AgentResults2', 'U') IS NOT NULL DROP TABLE #AgentResults2;

CREATE TABLE #AgentResults2  (FUser_id  varchar(48), FLoginDt datetime, FLogoutDt DateTime)

Insert Into #AgentResults2 (FUser_id , FLoginDt, FLogoutDt ) 
Select '30001','17/02/2012 8:09:23.117 AM' ,'17/02/2012 8:39:28.527 AM' UNION ALL
Select '30001','17/02/2012 8:50:26.087 AM','17/02/2012 9:31:32.040 AM' UNION ALL
Select '30001','17/02/2012 10:28:42.430 AM','17/02/2012 10:54:13.880 AM' UNION ALL
Select '30001','17/02/2012 10:59:20.567 AM','17/02/2012 12:00:36.030 PM' UNION ALL
Select '30001','17/02/2012 12:32:15.473 PM','17/02/2012 2:15:36.547 PM' UNION ALL
Select '30001','17/02/2012 12:49:48.177 PM','17/02/2012 2:10:01.097 PM' UNION ALL
Select '30001','17/02/2012 2:30:49.293 PM','17/02/2012 3:41:02.387 PM' UNION ALL
Select '30001','17/02/2012 3:44:05.800 PM','17/02/2012 4:01:33.613 PM' UNION ALL
Select '39300','17/02/2012 8:06:31.250 AM','17/02/2012 3:51:31.930 PM' UNION ALL
Select '39300','17/02/2012 10:15:08.923 AM','17/02/2012 10:21:29.833 AM' UNION ALL
Select '39363','17/02/2012 9:58:44.287 AM','17/02/2012 11:20:08.950 AM' UNION ALL
Select '39363','17/02/2012 11:20:29.203 AM','17/02/2012 1:27:36.717 PM' UNION ALL
Select '39363','17/02/2012 1:27:36.717 PM','17/02/2012 3:05:12.383 PM' UNION ALL
Select '39363','17/02/2012 3:05:31.527 PM','17/02/2012 4:57:13.733 PM' UNION ALL
Select '39363','17/02/2012 4:57:44.640 PM','17/02/2012 5:59:20.273 PM' UNION ALL
Select '39395','17/02/2012 9:37:14.353 AM','17/02/2012 10:15:52.397 AM' UNION ALL
Select '39395','17/02/2012 10:15:28.427 AM','17/02/2012 10:58:47.080 AM' UNION ALL
Select '39395','17/02/2012 10:57:03.590 AM','17/02/2012 11:53:47.933 AM' UNION ALL
Select '39395','17/02/2012 11:51:31.567 AM','17/02/2012 2:26:27.640 PM' UNION ALL
Select '39395','17/02/2012 2:31:30.247 PM','17/02/2012 4:04:44.217 PM' UNION ALL
Select '39395','17/02/2012 4:10:49.013 PM','17/02/2012 4:11:26.983 PM' UNION ALL
Select '39395','17/02/2012 4:17:16.813 PM','17/02/2012 5:55:47.187 PM' UNION ALL
Select '39395','17/02/2012 4:55:25.900 PM','17/02/2012 5:26:07.310 PM' ;

Select * from #AgentResults2;

IF OBJECT_ID('#AgentOutcome', 'U') IS NOT NULL DROP TABLE #AgentOutcome;

CREATE TABLE #AgentOutcome  (FUser_id  varchar(48), FLoginDt datetime, FLogoutDt DateTime)

Insert Into #AgentOutcome (FUser_id , FLoginDt, FLogoutDt ) 

Select '30001','17/02/2012 8:09:23.117 AM','17/02/2012 8:39:28.527 AM' UNION ALL
Select '30001','17/02/2012 8:50:26.087 AM','17/02/2012 9:31:32.040 AM' UNION ALL
Select '30001','17/02/2012 10:28:42.430 AM','17/02/2012 10:54:13.880 AM' UNION ALL
Select '30001','17/02/2012 10:59:20.567 AM','17/02/2012 12:00:36.030 PM' UNION ALL
Select '30001','17/02/2012 12:32:15.473 PM','17/02/2012 2:15:36.547 PM' UNION ALL
Select '30001','17/02/2012 2:30:49.293 PM','17/02/2012 3:41:02.387 PM' UNION ALL
Select '30001','17/02/2012 3:44:05.800 PM','17/02/2012 4:01:33.613 PM' UNION ALL
Select '39300','17/02/2012 8:06:31.250 AM','17/02/2012 3:51:31.930 PM' UNION ALL
Select '39363','17/02/2012 9:58:44.287 AM','17/02/2012 11:20:08.950 AM' UNION ALL
Select '39363','17/02/2012 11:20:29.203 AM','17/02/2012 3:05:12.383 PM' UNION ALL
Select '39363','17/02/2012 3:05:31.527 PM','17/02/2012 4:57:13.733 PM' UNION ALL
Select '39363','17/02/2012 4:57:44.640 PM','17/02/2012 5:59:20.273 PM' UNION ALL
Select '39395','17/02/2012 9:37:14.353 AM','17/02/2012 2:26:27.640 PM' UNION ALL
Select '39395','17/02/2012 2:31:30.247 PM','17/02/2012 4:04:44.217 PM' UNION ALL
Select '39395','17/02/2012 4:10:49.013 PM','17/02/2012 4:11:26.983 PM' UNION ALL
Select '39395','17/02/2012 4:17:16.813 PM','17/02/2012 5:55:47.187 PM' ;

Select * from #AgentOutcome;

DROP TABLE #AgentResults2;
DROP TABLE #AgentOutcome;

我已经检查了其他相关主题,它们确实接近但是更具体到聚合并且满足于min start& mx结束时间。

我使用的代码是

;with Ranges as ( 
    select FUser_id,FloginDt,FlogoutDt
    from #AgentResults2 
    union all 
        select r.FUser_id,r.FloginDt,t.FLogoutdt
    from 
        Ranges r 
            inner join 
        #AgentResults2  t 
            on 
                r.FUser_id = t.FUser_Id and DATEDIFF(ms,r.Flogoutdt,t.FloginDt) = 0
), 
ExtendedRanges as ( 
select FUser_id,MIN(FloginDt) as FloginDt,Flogoutdt
from Ranges 
group by FUser_ID,Flogoutdt
) 
select FUser_Id,FloginDt,MAX(Flogoutdt) 
from ExtendedRanges 
group by FUser_id,FloginDt 
order by 1
    OPTION (MAXRECURSION 0)

1 个答案:

答案 0 :(得分:1)

我认为这已经得到了它:

;With Ranges as (
    select
        a1.FUser_Id,a1.FLoginDt,a1.FLogoutDt
    from
        #AgentResults2 a1
            left join
        #AgentResults2 a_nooverlap_early
            on
                a1.FUser_id = a_nooverlap_early.FUser_id and
                a_nooverlap_early.FLoginDt < a1.FLoginDt and
                a_nooverlap_early.FLogoutDt >= a1.FLoginDt
    where
        a_nooverlap_early.FUser_id is null
    union all
    select r.FUser_Id,r.FLoginDt,a1.FLogoutDt
    from
        Ranges r
            inner join
        #AgentResults2 a1
            on
                r.FUser_id = a1.FUser_Id and
                r.FLogoutDt >= a1.FLoginDt and
                a1.FLogoutDt > r.FLogoutDt
)
select FUser_id,FLoginDt,MAX(FLogoutDt) as FLogoutDt from Ranges group by FUser_id,FLoginDt

Ranges CTE的第一部分查找FLoginDt与其他范围不重叠的所有时间段。然后,CTE的递归部分会尝试查找与这些时段的FLogoutDt重叠的任何其他时段,并采用后来的FLogoutDt。然后,最终选择会针对任何特定的FLogoutDtFUser_id组合获取最新的FLoginDt - 这应该是存在重叠的整个期间。

我还重写了您的示例数据,因此不需要SET DATEFORMAT DMY - 我显示的日期格式将始终安全/明确地由SQL Server转换为datetime

CREATE TABLE #AgentResults2  (FUser_id  varchar(48), FLoginDt datetime, FLogoutDt DateTime)

Insert Into #AgentResults2 (FUser_id , FLoginDt, FLogoutDt ) 
select '30001','2012-02-17T08:09:23.117','2012-02-17T08:39:28.527' union all
select '30001','2012-02-17T08:50:26.087','2012-02-17T09:31:32.040' union all
select '30001','2012-02-17T10:28:42.430','2012-02-17T10:54:13.880' union all
select '30001','2012-02-17T10:59:20.567','2012-02-17T12:00:36.030' union all
select '30001','2012-02-17T12:32:15.473','2012-02-17T14:15:36.547' union all
select '30001','2012-02-17T12:49:48.177','2012-02-17T14:10:01.097' union all
select '30001','2012-02-17T14:30:49.293','2012-02-17T15:41:02.387' union all
select '30001','2012-02-17T15:44:05.800','2012-02-17T16:01:33.613' union all
select '39300','2012-02-17T08:06:31.250','2012-02-17T15:51:31.930' union all
select '39300','2012-02-17T10:15:08.923','2012-02-17T10:21:29.833' union all
select '39363','2012-02-17T09:58:44.287','2012-02-17T11:20:08.950' union all
select '39363','2012-02-17T11:20:29.203','2012-02-17T13:27:36.717' union all
select '39363','2012-02-17T13:27:36.717','2012-02-17T15:05:12.383' union all
select '39363','2012-02-17T15:05:31.527','2012-02-17T16:57:13.733' union all
select '39363','2012-02-17T16:57:44.640','2012-02-17T17:59:20.273' union all
select '39395','2012-02-17T09:37:14.353','2012-02-17T10:15:52.397' union all
select '39395','2012-02-17T10:15:28.427','2012-02-17T10:58:47.080' union all
select '39395','2012-02-17T10:57:03.590','2012-02-17T11:53:47.933' union all
select '39395','2012-02-17T11:51:31.567','2012-02-17T14:26:27.640' union all
select '39395','2012-02-17T14:31:30.247','2012-02-17T16:04:44.217' union all
select '39395','2012-02-17T16:10:49.013','2012-02-17T16:11:26.983' union all
select '39395','2012-02-17T16:17:16.813','2012-02-17T17:55:47.187' union all
select '39395','2012-02-17T16:55:25.900','2012-02-17T17:26:07.310';