【问题标题】:How to count users logged with duration per date and 15 min interval如何计算每个日期的持续时间和 15 分钟间隔记录的用户数
【发布时间】:2019-10-21 07:04:27
【问题描述】:

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

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

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

这是示例数据

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

【问题讨论】:

  • 阅读overlap标签的详细信息。这应该有助于成功的一半。然后使用case处理duration根据每个区间的重叠程度计算。
  • this的回答也可能会激发一些想法。它处理每个小时间隔内的最大并发用户数。
  • 谢谢,我会检查两个。

标签: sql-server tsql


【解决方案1】:

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

这就是答案。

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

我可以使用交叉应用来更改它,但它现在有效。

所以,它返回这个数据:

date    interval    usersConnected  duracion
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
2019-08-25  07:00:00    2   1800
2019-08-25  07:15:00    2   1800
2019-08-25  07:30:00    2   1800
2019-08-25  07:45:00    2   1800
2019-08-25  08:00:00    2   1800
2019-08-25  08:15:00    2   1800
2019-08-25  08:30:00    2   1800
2019-08-25  08:45:00    2   1800
2019-08-25  09:00:00    2   1800
2019-08-25  09:15:00    2   1800
2019-08-25  09:30:00    2   1800
2019-08-25  09:45:00    2   1800
2019-08-25  10:00:00    2   1800
2019-08-25  10:15:00    2   1800
2019-08-25  10:30:00    2   1800
2019-08-25  10:45:00    2   1800
2019-08-25  11:00:00    2   1800
2019-08-25  11:15:00    2   1800
2019-08-25  11:30:00    2   1800
2019-08-25  11:45:00    2   1800
2019-08-25  12:00:00    2   1800
2019-08-25  12:15:00    2   1800
2019-08-25  12:30:00    2   1800
2019-08-25  12:45:00    2   1800
2019-08-25  13:00:00    2   1800
2019-08-25  13:15:00    2   1800
2019-08-25  13:30:00    2   1800
2019-08-25  13:45:00    2   1800
2019-08-25  14:00:00    2   1800
2019-08-25  14:15:00    2   1800
2019-08-25  14:30:00    2   1800
2019-08-25  14:45:00    2   1800
2019-08-25  15:00:00    2   1800
2019-08-25  15:15:00    2   1800
2019-08-25  15:30:00    2   1800
2019-08-25  15:45:00    2   1800
2019-08-25  16:00:00    2   1800
2019-08-25  16:15:00    2   1800
2019-08-25  16:30:00    2   1800
2019-08-25  16:45:00    2   1800
2019-08-25  17:00:00    2   1800
2019-08-25  17:15:00    2   1800
2019-08-25  17:30:00    2   1800
2019-08-25  17:45:00    2   1800
2019-08-25  18:00:00    2   1800
2019-08-25  18:15:00    2   1800
2019-08-25  18:30:00    2   1800
2019-08-25  18:45:00    2   1800
2019-08-25  19:00:00    2   1800
2019-08-25  19:15:00    2   1800
2019-08-25  19:30:00    2   1800
2019-08-25  19:45:00    2   1800
2019-08-25  20:00:00    2   1800
2019-08-25  20:15:00    2   1800
2019-08-25  20:30:00    2   1800
2019-08-25  20:45:00    2   1800
2019-08-25  21:00:00    2   1800
2019-08-25  21:15:00    2   1800
2019-08-25  21:30:00    2   1800
2019-08-25  21:45:00    2   1800
2019-08-25  22:00:00    2   1800
2019-08-25  22:15:00    2   1800
2019-08-25  22:30:00    2   1800
2019-08-25  22:45:00    2   1800
2019-08-25  23:00:00    2   1800
2019-08-25  23:15:00    2   1800
2019-08-25  23:30:00    2   1800
2019-08-25  23:45:00    2   1800
2019-08-26  00:00:00    2   1800
2019-08-26  00:15:00    2   1800
2019-08-26  00:30:00    2   1800
2019-08-26  00:45:00    2   1800
2019-08-26  01:00:00    2   1800
2019-08-26  01:15:00    2   1800
2019-08-26  01:30:00    2   1800
2019-08-26  01:45:00    2   1800
2019-08-26  02:00:00    2   1800
2019-08-26  02:15:00    2   1800
2019-08-26  02:30:00    2   1800
2019-08-26  02:45:00    2   1800
2019-08-26  03:00:00    2   1800
2019-08-26  03:15:00    2   1800
2019-08-26  03:30:00    2   1800
2019-08-26  03:45:00    2   1800
2019-08-26  04:00:00    2   1800
2019-08-26  04:15:00    2   1800
2019-08-26  04:30:00    2   1800
2019-08-26  04:45:00    2   1800
2019-08-26  05:00:00    2   1800
2019-08-26  05:15:00    2   1800
2019-08-26  05:30:00    2   1800
2019-08-26  05:45:00    2   1800
2019-08-26  06:00:00    2   1800
2019-08-26  06:15:00    2   1800
2019-08-26  06:30:00    2   1800
2019-08-26  06:45:00    2   1800
2019-08-26  07:00:00    2   1800
2019-08-26  07:15:00    2   1800
2019-08-26  07:30:00    2   1800
2019-08-26  07:45:00    2   1800
2019-08-26  08:00:00    2   1800
2019-08-26  08:15:00    2   1800
2019-08-26  08:30:00    2   1800
2019-08-26  08:45:00    2   1800
2019-08-26  09:00:00    2   1800
2019-08-26  09:15:00    2   1800
2019-08-26  09:30:00    2   1800
2019-08-26  09:45:00    2   1800
2019-08-26  10:00:00    2   1800
2019-08-26  10:15:00    2   1800
2019-08-26  10:30:00    2   1800
2019-08-26  10:45:00    2   1800
2019-08-26  11:00:00    2   1800
2019-08-26  11:15:00    2   1800
2019-08-26  11:30:00    2   1800
2019-08-26  11:45:00    2   1800
2019-08-26  12:00:00    2   1800
2019-08-26  12:15:00    2   1800
2019-08-26  12:30:00    2   1800
2019-08-26  12:45:00    2   1800
2019-08-26  13:00:00    2   1800
2019-08-26  13:15:00    2   1800
2019-08-26  13:30:00    2   1800
2019-08-26  13:45:00    2   1477

【讨论】:

  • 您可能想尝试将其重新设计为一系列公用表表达式 (CTE) 以减少重复并将其分解为更简单的步骤,例如with Events as ( select userId, [login] = CAST(loginDate AS DATETIME) + CAST(loginTime AS DATETIME), [logout] = CAST(logoutDate AS DATETIME) + CAST(logoutTime AS DATETIME) from @events ) ), EventsInIntervals as ( select ... from Events ) select ...;This 答案显示了一个可怕的例子。查询优化器通常会将整个粉碎放在一起,不使用递归,以获得良好的性能。
  • 您也可以select CTE 的任何中间结果,方便测试和调试。只需更改最后的 select 语句即可。
  • 再次感谢,这会很有帮助,我会尝试发布更新。你帮了我很多!
猜你喜欢
  • 2013-01-23
  • 1970-01-01
  • 2014-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 2021-12-22
相关资源
最近更新 更多