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

Sql 选择并分组彼此间隔30分钟的记录,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,在SQLServer2008中有一个表,可以捕获页面访问,类似于IIS日志或谷歌分析,没有什么特别之处 该表包含以下列: [ID]、[Username]、[URL]、[Created]、[Browser]、[BrowserVersion]、[HostName]、[IPAddress]、[OperatingSystem]、[UrlReferer] 下图显示了按创建日期(创建列)排序的查询输出,以降序格式表示/列出所有页面点击。出于隐私目的,URL和用户名被省略 我想做的是编写一个查询,将所有行分

在SQLServer2008中有一个表,可以捕获页面访问,类似于IIS日志或谷歌分析,没有什么特别之处

该表包含以下列:

[ID]、[Username]、[URL]、[Created]、[Browser]、[BrowserVersion]、[HostName]、[IPAddress]、[OperatingSystem]、[UrlReferer]

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

我想做的是编写一个查询,将所有行分组到一个相同的IP地址和用户名,其中与最后一条记录发生的时间差小于30分钟,或者换言之,只选择/返回相同IP地址和用户名的最后一条记录,并删除之前的所有其他行

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


这会让你有一段路要走。它会查找在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”的开始日期/时间


这应该能让你走到一半。它会查找在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”的开始日期/时间


首先,你的要求可以解释不止一种方式,所以让我统计一下我认为你想要什么。。。我想你是说,当给定的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函数查看前一行中的值,并计算已过去的分钟数。
分区依据
将此计算限制到每个IP地址

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


最后,“sessionInfo”CTE建立在第二个基础上。使用LEAD功能,我们期待看到下一个会话从何处开始。当当前行的会话结束时,此值被视为。我们最终得到的是IP地址、会话开始和会话结束。现在您已经有了这些,应该可以很容易地将其连接到原始表并将其分组。

首先,您的需求可以用多种方式进行解释,所以让我来统计一下您想要什么。。。我想你是说,当给定的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函数查看前一行中的值,并计算已过去的分钟数。
分区依据
将此计算限制到每个IP地址

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


最后,“sessionInfo”CTE建立在第二个基础上。使用LEAD功能,我们期待看到下一个会话从何处开始。当当前行的会话结束时,此值被视为。我们最终得到的是IP地址、会话开始和会话结束。现在您已经有了这些,应该可以很容易地将其连接到原始表并将其分组。

Microsoft SQL的优点在于,它们具有非标准的“选择顶部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
从中选择*
(
选择
身份证件
ipAdress,
创建,
(
选择
第一名
创建
如前所述,来自tbl
其中t上一个.ipAdress=t.ipAdress

和tPrevious.createdMicrosoft 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
从中选择*
(
选择
身份证件
ipAdress,
创建,
(
选择
第一名
创建
如前所述,来自tbl
其中t上一个.ipAdress=t.ipAdress

和tPrevious.createdWhat是您想要的输出?@sgedes想象一个由blob中没有任何一行定义的“blob”行与其他每一行的距离超过30分钟。他希望每个IPAddress和Username的所有这些“blob”都是分组行。问题是您需要将时间括在30分钟的块中,并按IP和用户名将它们分组时间块。你不能只说“彼此相隔30分钟内”因为如果记录分布超过30分钟,它将不知道如何对它们进行分组。请看:@Russell Fox链接的问题是另一个问题。他想按30分钟的间隔对行进行桶/直方图划分。Amir Kayvan的问题是将所有行“blob”在一起,只要它们的距离小于30分钟,例如sessi在检测时。您想要的输出是什么?@sgedes想象一个“blob”行,该行由blob中没有任何行定义