我需要一个查询来将团队分配给一系列用户。数据如下所示:
UserId Category Team
1 A null
2 A null
3 B null
4 B null
5 A null
6 B null
8 A null
9 B null
11 B null团队应该通过按用户and排序来创建,第一个用户and成为团队编号,连续的A是该团队的一部分,随后的B也是团队的一部分。B之后的第一个A开始了一个新的团队。始终至少有一个A和一个B。因此,在更新之后,数据应该如下所示:
UserId Category Team
1 A 1
2 A 1
3 B 1
4 B 1
5 A 5
6 B 5
8 A 8
9 B 8
11 B 8编辑:需要补充的是,用户id并不总是递增1。我编辑了示例数据以显示我的意思。此外,团队ID不一定严格是第一个用户的id,只要他们最终正确分组即可。例如,用户1-4可以都在团队“1”中,用户5和6在团队“2”中,用户8,9和11在团队“3”中。
发布于 2013-03-02 03:46:48
实际上,我最终选择了以下内容。它在半小时内完成了所有3个million+行的测试。
declare @userid int
declare @team int
declare @category char(1)
declare @lastcategory char(1)
set @userid = 1
set @lastcategory='B'
set @team=0
while @userid is not null
begin
select @category = category from users where userid = @userid
if @category = 'A' and @lastcategory = 'B'
begin
set @team = @userid
end
update users set team = @team where userid = @userid
set @lastcategory = @category
select @userid = MIN(userid) from users where userid > @userid
End发布于 2013-02-28 01:46:26
首先,您可以用递增的数字标记每一行。然后,您可以使用left join查找之前的用户。如果前一个用户的类别为'B',而当前用户的类别为'A',这意味着新团队的开始。然后,团队编号是在当前UserId之前启动新团队的最后一个UserId。
使用SQL Server 2008语法:
; with numbered as
(
select row_number() over (order by UserId) rn
, *
from Table1
)
, changes as
(
select cur.UserId
, case
when prev.Category = 'B' and cur.Category = 'A' then cur.UserId
when prev.Category is null then cur.UserId
end as Team
from numbered cur
left join
numbered prev
on cur.rn = prev.rn + 1
)
update t1
set Team = team.Team
from Table1 t1
outer apply
(
select top 1 c.Team
from changes c
where c.UserId <= t1.UserId
and c.Team is not null
order by
c.UserId desc
) as team;Example at SQL Fiddle.
发布于 2013-02-28 01:46:55
您可以使用递归CTE来完成此操作:
with userCTE as
(
select UserId
, Category
, Team = UserId
from users where UserId = 1
union all
select users.UserId
, users.Category
, Team = case when users.Category = 'A' and userCTE.Category = 'B' then users.UserId else userCTE.Team end
from userCTE
inner join users on users.UserId = userCTE.UserId + 1
)
update users
set Team = userCTE.Team
from users
inner join userCTE on users.UserId = userCTE.UserId
option (maxrecursion 0)SQL Fiddle demo。
编辑:
您可以更新CTE以获取此go:
with userOrder as
(
select *
, userRank = row_number() over (order by userId)
from users
)
, userCTE as
(
select UserId
, Category
, Team = UserId
, userRank
from userOrder where UserId = (select min(UserId) from users)
union all
select users.UserId
, users.Category
, Team = case when users.Category = 'A' and userCTE.Category = 'B' then users.UserId else userCTE.Team end
, users.userRank
from userCTE
inner join userOrder users on users.userRank = userCTE.userRank + 1
)
update users
set Team = userCTE.Team
from users
inner join userCTE on users.UserId = userCTE.UserId
option (maxrecursion 0)SQL Fiddle demo。
编辑:
对于较大的数据集,您需要添加maxrecursion查询提示;我已经编辑了前面的查询以显示这一点。来自联机丛书:
指定此查询允许的最大递归数。number是介于0和32767之间的非负整数。如果指定0,则不应用任何限制。
在本例中,我将其设置为0,即不限制递归。
Query Hints。
https://stackoverflow.com/questions/15118221
复制相似问题