2017-01-16 79 views
0

我们有一个活动数据库,记录用户与网站的交互情况,存储包含诸如[UserId]和[LogDate]等数据的日志。微软SQL服务器每隔30分钟计数一次

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分钟。

这是可能的SQL?我需要一种针对用户日志检查用户的每个日志的方法,如果它们之间的时间差超过30分钟,它应该算作一个独特的会话。

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

谢谢。

+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); 
+0

顶部声明奏效,谢谢。我在max(log_date)之后添加了一个闭括号以平衡开括号,并在括号内添加“userid by orderrid”。再次感谢。 –

0

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

我们想要识别的是“开始日志” - 标记会话开始的日志。我们不想识别任何其他日志。

我们如何定义“起始日志”?这是一个在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) 
    ) 
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语句来标记差异大于阈值的新登录名。

如果找不到前一行,则lag函数将返回null。