2013-05-02 55 views
1

在sql server 2008中有一张表,其中捕获了页面访问,与IIS日志或Google Analytics类似,没有什么太花哨。选择并组合记录彼此相距30分钟

该表具有如列:

[ID],[用户名],[URL],[创建],[浏览器],[BrowserVersion],[主机名],[ip地址],[OperatingSystem的] ,[UrlReferrer]

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

Query

我想什么做的是一个查询写信给组中所有行之一,从去年创纪录的次数时间差小于30分钟,相同的ip地址和用户名或者换句话说,选择/只返回同一IPAddress和用户名的最后一条记录,并在此之前删除所有其他行。

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

enter image description here

+2

你想要的输出是什么? – sgeddes 2013-05-02 23:50:42

+0

@sgeddes想象一下由blob中的任何一行定义的行的“blob”与每个其他行相距超过30分钟。他希望每个IP地址和用户名的所有这些“斑点”都是分组行。 – Patashu 2013-05-02 23:54:56

+0

问题是,您需要将时间限制在30分钟的区块中,并将它们按IP和TimeChunk分组。你不能只说“彼此30分钟内”,因为如果记录分散超过30分钟,它将不知道如何分组。 – 2013-05-03 00:04:21

回答

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

感谢您的回答;但是,这是一个长时间运行的查询,并不能满足我在寻找的内容。我期待的最终结果接近Patashu所描述的。 – 2013-05-03 03:11:56

+0

不知道我明白,Patashu说你*不需要直方图,并且想要将它们“聚集”在一起,这就是我所做的。 – 2013-05-03 07:09:46

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地址,会话开始和会话结束。现在你已经拥有这些了,应该很容易将它加入到原始表格中并对其进行分组。

+0

LEAD和LAG函数似乎在SQL Server 2008中不可用! – 2013-05-03 03:38:29

+0

Bah!忘记我的测试机器是在2012年。查看这个关于刺激2008年的领先/滞后的链接,也许它会有所帮助。 http://www.rafael-salas.com/2008/05/t-sql-lead-and-lag-functions.html?m=1 – dazedandconfused 2013-05-03 10:11:57

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