Sql server SQL Server:按超时划分的行数
我有一个包含一系列(IP varchar(15),DateTime datetime2)值的表。每行对应于用户发出的HTTP请求。我想为这些行分配会话编号。不同的IP地址有不同的会话号。如果最后一个请求超过30分钟,则应为同一IP分配新的会话号。以下是一个示例输出:Sql server SQL Server:按超时划分的行数,sql-server,tsql,sql-server-2012,olap,row-number,Sql Server,Tsql,Sql Server 2012,Olap,Row Number,我有一个包含一系列(IP varchar(15),DateTime datetime2)值的表。每行对应于用户发出的HTTP请求。我想为这些行分配会话编号。不同的IP地址有不同的会话号。如果最后一个请求超过30分钟,则应为同一IP分配新的会话号。以下是一个示例输出: IP, DateTime, SessionNumber, RequestNumber 1.1.1.1, 2012-01-01 00:01, 1, 1 1.1.1.1, 2012-01
IP, DateTime, SessionNumber, RequestNumber
1.1.1.1, 2012-01-01 00:01, 1, 1
1.1.1.1, 2012-01-01 00:02, 1, 2
1.1.1.1, 2012-01-01 00:03, 1, 3
1.1.1.2, 2012-01-01 00:04, 2, 1 --different IP => new session number
1.1.1.2, 2012-01-01 00:05, 2, 2
1.1.1.2, 2012-01-01 00:40, 3, 1 --same IP, but last request 35min ago (> 30min)
第1列和第2列为输入,第3列和第4列为所需输出。该表显示了两个用户
由于基础is表确实很大,如何有效地解决这一问题?我更喜欢对数据进行少量恒定的传递(一次或两次)。这里有几次尝试
;WITH CTE1 AS
(
SELECT *,
IIF(DATEDIFF(MINUTE,
LAG(DateTime) OVER (PARTITION BY IP ORDER BY DateTime),
DateTime) < 30,0,1) AS SessionFlag
FROM Sessions
), CTE2 AS
(
SELECT *,
SUM(SessionFlag) OVER (PARTITION BY IP
ORDER BY DateTime) AS IPSessionNumber
FROM CTE1
)
SELECT IP,
DateTime,
DENSE_RANK() OVER (ORDER BY IP, IPSessionNumber) AS SessionNumber,
ROW_NUMBER() OVER (PARTITION BY IP, IPSessionNumber
ORDER BY DateTime) AS RequestNumber
FROM CTE2
但是,这会将排序操作的数量增加到4。下面是一个版本,它使用表变量和行号来创建一个可以在递归CTE中使用的ID。比较游标和一个查询(由Martin提供)版本的性能可能是值得的
CREATE TABLE #T
(
IP varchar(15),
DateTime datetime,
ID int,
primary key (IP, ID)
)
insert into #T(IP, DateTime, ID)
select IP, DateTime, row_number() over(partition by IP order by DateTime)
from #sessionRequests
;with C as
(
select IP,
ID,
DateTime,
1 as Session
from #T
where ID = 1
union all
select T.IP,
T.ID,
T.DateTime,
C.Session + case when datediff(minute, C.DateTime, T.DateTime) >= 30 then 1 else 0 end
from #T as T
inner join C
on T.IP = C.IP and
T.ID = C.ID + 1
)
SELECT IP,
DateTime,
dense_rank() over(order by IP, Session) as SessionNumber,
row_number() over(partition by IP, Session order by DateTime) as RequestNumber
from C
order by IP, DateTime, SessionNumber, RequestNumber
option (maxrecursion 0)
什么版本的SQL Server?如果2012年,新的
OVER
子句功能将有所帮助。如果来自两个IP的交叉请求,它们的会话不会混淆吗?我必须说,t-SQL缺少自定义的、有状态的聚合功能。这将使此查询变得简单,并且只需要一个排序操作。@usr-可能还值得评估一个游标和一个#temp
表!我不确定这是否有帮助。我实际上做了一个动态光标解决方案,同时希望你能发布一个单一的查询解决方案(你做到了!)。它慢了20倍。也许我仍然会使用它,因为我可以通过更复杂的计算更好地扩展它。我们在这里所做的基本操作是“扫描”(例如)。scan=在一个有序序列上任意聚合,同时每个输入元素输出一个元素,而不是整个组/序列的一个元素。我喜欢这个版本,因为它很容易扩展,几乎像基于光标的方法。我将其更改为使用临时表,该表修复了优化器问题(表变量没有统计数据)。此外,我还验证了该代码是否有效。谢谢
CREATE TABLE #T
(
IP varchar(15),
DateTime datetime,
ID int,
primary key (IP, ID)
)
insert into #T(IP, DateTime, ID)
select IP, DateTime, row_number() over(partition by IP order by DateTime)
from #sessionRequests
;with C as
(
select IP,
ID,
DateTime,
1 as Session
from #T
where ID = 1
union all
select T.IP,
T.ID,
T.DateTime,
C.Session + case when datediff(minute, C.DateTime, T.DateTime) >= 30 then 1 else 0 end
from #T as T
inner join C
on T.IP = C.IP and
T.ID = C.ID + 1
)
SELECT IP,
DateTime,
dense_rank() over(order by IP, Session) as SessionNumber,
row_number() over(partition by IP, Session order by DateTime) as RequestNumber
from C
order by IP, DateTime, SessionNumber, RequestNumber
option (maxrecursion 0)