我们有一个活动数据库,记录用户与网站的互动,存储包含[UserId]和[LogDate]等值的日志,例如。
UserId|LogDate
123 |2017-01-01 11:17:35.190
我试图找出不同用户会话的计数。
通过统计不同的用户,这很容易:
SELECT COUNT(DISTINCT UserId) FROM ActivityDatabase.dbo.Logs
但是,如果用户的日志超过前一个日志超过30分钟,我需要多次计算一次,因为这会被归类为新会话。
会话定义为在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);
答案 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)
)