Sql server 如何统计以每个日期的持续时间和15分钟间隔登录的用户

Sql server 如何统计以每个日期的持续时间和15分钟间隔登录的用户,sql-server,tsql,Sql Server,Tsql,我想根据登录和注销日期时间列,按日期和15分钟间隔确定连接的用户,并根据登录时间和实际间隔,以秒为单位计算该事件的持续时间。在某些情况下,用户连接到系统的时间超过10小时,连接可能在第二天完成 因此,我有一个间隔15分钟从00:00到23:59的间隔表,还有一个包含登录数据的表 我尝试使用这两个表来获取interval表中每个interval的登录事件,但没有成功 这是示例数据 DECLARE @events TABLE ( userId VARCHAR(10) , loginD

我想根据登录和注销日期时间列,按日期和15分钟间隔确定连接的用户,并根据登录时间和实际间隔,以秒为单位计算该事件的持续时间。在某些情况下,用户连接到系统的时间超过10小时,连接可能在第二天完成

因此,我有一个间隔15分钟从00:00到23:59的间隔表,还有一个包含登录数据的表

我尝试使用这两个表来获取interval表中每个interval的登录事件,但没有成功

这是示例数据

DECLARE @events TABLE
(
    userId VARCHAR(10)
    , loginDate DATE
    , loginTime TIME(0)
    , logoutDate DATE
    , logoutTime TIME(0)
)

INSERT INTO @events 
SELECT '1010862178', '2019-08-25', '06:56:59', '2019-08-25', '21:51:56'
UNION ALL SELECT '1010862178', '2019-08-25', '21:51:56', '2019-08-26', '13:56:24'
UNION ALL SELECT '1016063857', '2019-08-25', '05:56:10', '2019-08-25', '14:14:33'
UNION ALL SELECT '1016063857', '2019-08-25', '14:14:33', '2019-08-26', '13:58:13'
这是事件表

结果应该是这样的:

date        interval    usersConnected  duration
2019-08-25  05:45:00    1               230
2019-08-25  06:00:00    1               900
2019-08-25  06:15:00    1               900
2019-08-25  06:30:00    1               900
2019-08-25  06:45:00    2               1081
我希望你们能帮助我!提前谢谢

编辑:结果表的开头应如下所示:

date        interval    usersConnected  duration
2019-08-25  05:45:00    1               230
2019-08-25  06:00:00    1               900
2019-08-25  06:15:00    1               900
2019-08-25  06:30:00    1               900
2019-08-25  06:45:00    2               1081

好的,在写了几个小时的查询之后,我终于找到了一个解决方案,也许这不是一个优雅的解决方案,但它是有效的,所以现在的挑战是用更少的代码来解决这个问题

这是答案

DECLARE @events TABLE
(
    userId VARCHAR(10)
    , loginDate DATE
    , loginTime TIME(0)
    , logoutDate DATE
    , logoutTime TIME(0)
)

INSERT INTO @events 
SELECT '1010862178', '2019-08-25', '06:56:59', '2019-08-25', '21:51:56'
UNION ALL SELECT '1010862178', '2019-08-25', '21:51:56', '2019-08-26', '13:56:24'
UNION ALL SELECT '1016063857', '2019-08-25', '05:56:10', '2019-08-25', '14:14:33'
UNION ALL SELECT '1016063857', '2019-08-25', '14:14:33', '2019-08-26', '13:58:13'

/* Other tables are:
    dates table:  contains only two dates '2019-08-25' and '2019-08-26'
    intervals table: contains intervals from 00:00:00 to 23:45:00
*/

select 
    convert(date, i.intervalStart) [date]
    , convert(time(0), i.intervalStart) [interval]
    , count(distinct userId) usersConnected -- distinct prevent duplicates on overlaping login and logout hours
    , sum(case 
        when datediff(second, iif([login] > i.intervalStart, [login], i.intervalStart) , iif(logout < i.intervalEnd, logout, i.intervalEnd)) < 0 then 900
        else datediff(second, iif([login] > i.intervalStart, [login], i.intervalStart) , iif(logout < i.intervalEnd, logout, i.intervalEnd))
      end) duracion
 from (
 select userId
    , [login] = CAST(loginDate AS DATETIME) + CAST(loginTime AS DATETIME)
    , [logout] = CAST(logoutDate AS DATETIME) + CAST(logoutTime AS DATETIME)
 from @events ) c
 inner join (select intervalStart = CAST([date] AS DATETIME) + CAST([start] AS DATETIME)
        , intervalEnd = CAST([date] AS DATETIME) + CAST([end] AS DATETIME)
     from dbo.dates, dbo.intervals) m
     on c.[login] between  m.intervalStart and m.intervalEnd
 inner join (select
   intervalStart = CAST([date] AS DATETIME) + CAST([start] AS DATETIME)
        , intervalEnd = CAST([date] AS DATETIME) + CAST([end] AS DATETIME)
     from dbo.dates, dbo.intervals) i
 on i.intervalStart  between m.intervalStart and c.logout
 group by convert(date, i.intervalStart)
    , convert(time(0), i.intervalStart)
 order by 1, 2

阅读标签的详细信息。这将有助于完成一半的战斗。然后根据每个间隔的重叠程度来处理持续时间的计算。答案也可能引发一些想法。它处理每个小时间隔内的最大并发用户数。谢谢,我将检查这两个。您可能希望尝试将其重新设计为一系列通用表表达式CTE,以减少重复,并将其分解为更简单的步骤,例如,使用事件作为select userId、[login]=CASTloginDate as DATETIME+CASTloginTime as DATETIME,[注销]=CASTlogoutDate AS DATETIME+CASTlogoutTime AS DATETIME from@events,EventsInIntervals AS select…from events select…;。答案显示了一个糟糕的例子。查询优化器通常会将整个smash放在一起,没有递归,以获得良好的性能。您还可以从CTE中选择任何中间结果,方便测试和调试。只需更改最终的select语句。再次感谢,这将很有帮助,我将尝试发布更新。你帮了我很多!