选择并分组记录彼此间隔30分钟

时间:2013-05-02 23:23:24

标签: sql sql-server sql-server-2008

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

该表包含以下列:

[ID],[用户名],[URL],[已创建],[浏览器],[BrowserVersion],[HostName],[IPAddress],[OperatingSystem],[UrlReferrer]

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

Query

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

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

enter image description here

3 个答案:

答案 0 :(得分: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地址,会话开始和会话结束。现在您已经拥有了这些内容,将其加入原始表并将其组合起来应该很容易。

答案 1 :(得分: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

答案 2 :(得分:0)

Microsoft SQL的优点在于它们具有非标准的“选择顶部...”的可能性;这就是你可以在这里使用的:

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