Sql server 如何统计以每个日期的持续时间和15分钟间隔登录的用户
我想根据登录和注销日期时间列,按日期和15分钟间隔确定连接的用户,并根据登录时间和实际间隔,以秒为单位计算该事件的持续时间。在某些情况下,用户连接到系统的时间超过10小时,连接可能在第二天完成 因此,我有一个间隔15分钟从00:00到23:59的间隔表,还有一个包含登录数据的表 我尝试使用这两个表来获取interval表中每个interval的登录事件,但没有成功 这是示例数据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
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语句。再次感谢,这将很有帮助,我将尝试发布更新。你帮了我很多!