Microsoft SQL服务器计数每30分钟一次

时间:2017-01-16 15:15:48

标签: sql sql-server

我们有一个活动数据库,记录用户与网站的互动,存储包含[UserId]和[LogDate]等值的日志,例如。

UserId|LogDate
123   |2017-01-01 11:17:35.190

我试图找出不同用户会话的计数。

通过统计不同的用户,这很容易:

SELECT COUNT(DISTINCT UserId) FROM ActivityDatabase.dbo.Logs

但是,如果用户的日志超过前一个日志超过30分钟,我需要多次计算一次,因为这会被归类为新会话。

会话定义为在30分钟的时间范围内有一个日志。例如:

  1. 如果用户在13.30创建日志,则为不同用户的值 随着时间的推移,会议将是1。
  2. 如果用户在13.40创建另一个日志,则计数应该仍为1,因为它在上一个日志的30分钟内。
  3. 如果用户在14.20创建了另一个日志,则计数应为2,因为这是在上一个日志之后的30分钟。
  4. 这在SQL中可行吗?我需要一种方法来检查用户针对先前用户日志的每个日志,如果这些日志之间的时间差超过30分钟,则应将其视为唯一会话。

    SQL的输出应该是一个数字而不是按时间段分解。

    谢谢。

3 个答案:

答案 0 :(得分:2)

会话化有点棘手。让我告诉你如何做到这一点。也许这会解决你的问题:

select userid, min(log_date) as session_start,
       dateadd(minute, 30, max(log_date)) as session_end,
       row_number() over () as session_id
from (select l.*,
             sum(case when log_date < dateadd(minute, 30, prev_logdate)
                      then 0 else 1
                 end) over (partition by userid order by logdate
                           ) as grp
      from (select l.*,
                   lag(logdate) over (partition by userid order by logdate) as prev_logdate
            from ActivityDatabase.dbo.Logs l
           ) l
      ) l
group by userid, grp;

如果您想要在给定时间点获得唯一身份用户的数量,那么:

with s as (
      select userid, min(log_date) as session_start,
             dateadd(minute, 30, max(log_date) as session_end,
             row_number() over () as session_id
      from (select l.*,
                   sum(case when log_date < dateadd(minute, 30, prev_logdate)
                            then 0 else 1
                       end) over (partition by userid order by logdate
                                 ) as grp
            from (select l.*,
                         lag(logdate) over (partition by userid order by logdate) as prev_logdate
                  from ActivityDatabase.dbo.Logs l
                 ) l
            ) l
      group by userid, grp
     )
select count(*)
from s
where @datetime between session_start and session_end;

在给定时间内更强力的替代方案是:

select count(distinct userid)
from ActivityDatabase.dbo.Logs l
where @datetime between log_date and dateadd(minute, 30, log_date);

答案 1 :(得分:1)

如果您使用的是sql server 2012或更高版本,我会使用滞后函数查找上一行,然后您可以比较两个日期时间以查看差异是否大于30分钟

select
userId,
LogDate,
 LAG(LogDate, 1,0) OVER (PARTITION BY userId ORDER BY LogDate) AS PreviousLogDate
from logTbl

然后,您可以添加datediff和case语句来标记差异大于阈值的新登录。

如果没有找到前一行,则滞后函数将返回null。

答案 2 :(得分:0)

如果您正在使用您尝试使用的定义,则编写SQL会变得容易得多。

我们想要识别的是&#34;开始记录&#34; - 标记会话开始的日志。我们不想识别任何其他日志。

我们如何定义&#34;开始日志&#34;?它是一个在它之前30分钟内没有另一个日志的日志。

SELECT COUNT(*)
FROM ActivityDatabase.dbo.Logs l1
WHERE NOT EXISTS (
    SELECT * FROM ActivityDatabase.dbo.Logs l2
    WHERE l1.UserId = l2.UserId AND
          l2.LogDate < l1.LogDate AND
          l2.LogDate >= DATEADD(minute,-30,l1.LogDate)
    )