1

在 sql server 2008 中有一个表,其中捕获了页面访问,类似于 IIS 日志或 Google Analytics,没什么太花哨的。

该表具有以下列:

[ID]、[用户名]、[URL]、[已创建]、[浏览器]、[浏览器版本]、[主机名]、[IPAddress]、[操作系统]、[UrlReferrer]

下图说明了按创建日期(创建列)排序的查询输出,以降序格式表示/列出所有页面点击。出于隐私目的,省略了 URL 和用户名。

询问

我想要做的是编写一个查询,将所有行分组到一个相同的 IPAddress 和用户名的最后记录发生的时间差小于 30 分钟,或者换句话说,仅选择/返回相同 IPAddress 的最后一条记录和用户名并消除之前的所有其他行。

期望的结果只是那些旁边带有箭头的行(下图):

在此处输入图像描述

4

3 回答 3

1

首先,您的要求可以用多种方式解释,所以让我统计一下我认为您想要什么...我认为您是说当给定 IP 地址有 30 分钟不活动时会话结束。因此,如果一个 IP 地址每分钟访问一个站点 2 小时,然后休息 30 分钟,这代表一个会话。假设这是你的意图......

您可以使用 LEAD 和 LAG 来帮助您识别会话。我的测试数据由一个 Id 列、一个 IPAddress 列和一个 Created 列组成。这是代码,解释如下...

WITH t1 AS 
(
    SELECT 
        * 
        , DATEDIFF(minute, LAG(Created, 1, 0) OVER (PARTITION BY IPAddress ORDER BY Created), [Created]) AS SinceLastAccess
    FROM 
        IISLog
), sessionStarts AS 
(
    SELECT 
        * 
    FROM 
        t1
    WHERE 
        SinceLastAccess >= 30
), sessionInfo AS 
(
    SELECT 
        IPAddress
        , Created AS SessionStart
        , LEAD(Created, 1, '2025-01-01') OVER (PARTITION BY IPAddress ORDER BY CREATED) AS SessionEnd
    FROM 
        sessionStarts
)

SELECT * FROM sessionInfo

第一个 CTE (t1) 选择数据,但添加了一个名为 的列SinceLastAccess。这个新列使用 LAG 函数查看前一行中的值并计算已经过去了多少分钟。将此计算PARTITION BY限制到每个 IP 地址。

第二个 CTE (sessionStarts) 只是从 t1 中选择SinceLastAccess值大于 30 的那些行。这有效地告诉我们每个会话的开始。

最后,`sessionInfo' CTE 建立在第二个之上。使用 LEAD 函数,我们期待看到下一个会话从哪里开始。该值被认为是当前行的会话结束时。我们最终得到的是一个 IP 地址、会话开始和会话结束。现在你有了这些,应该很容易将它加入原始表并将其分组。

于 2013-05-03T02:25:39.230 回答
0

Microsoft SQL 的伟大之处在于它们具有非标准的“select top n ...”可能性;这就是你可以在这里使用的:

select * from

(
select
id,
ipAdress,
created,
(
select
top 1
created 
from tbl as tPrevious
where tPrevious.ipAdress=t.ipAdress
and tPrevious.created<t.created
order by created desc
) as previousCreated
from tbl as t
) as joined

where
previousCreated is not null 
and DATEDIFF(min, created,previousCreated) between 0 and 30
于 2013-05-03T04:54:05.137 回答
0

这应该会让你成功。它会查找在 30 分钟后没有另一个条目的所有条目(反之亦然,查找在它之前没有另一个 30 分钟的条目)

这应该为您提供每个条目“blob”结束的日期/时间。

SELECT m1.IpAddress, m1.DateCreated
FROM MyLog m1 LEFT OUTER JOIN MyLog m2 
                 ON m1.IpAddress = m2.IpAddress AND 
                    DATEDIFF(minute, m1.DateCreated, m2.DateCreated) BETWEEN 0 AND 30
WHERE m2.DateCreated IS NULL

这应该为您提供每个“blob”开始的日期/时间。

SELECT m1.IpAddress, m1.DateCreated
FROM MyLog m1 LEFT OUTER JOIN MyLog m2 
                 ON m1.IpAddress = m2.IpAddress AND 
                    DATEDIFF(minute, m2.DateCreated, m1.DateCreated) BETWEEN 0 AND 30
WHERE m2.DateCreated IS NULL
于 2013-05-03T00:37:16.403 回答