我需要一个查询来将团队分配给一系列用户。数据如下所示:
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
应该通过按用户ID排序来创建团队,并且第一个用户ID变为团队编号,连续的A是该团队的一部分,后面的B也是如此。在Bs开始新球队之后的第一个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'上
答案 0 :(得分:4)
首先,您可以使用不断增加的数字标记每一行。然后,您可以使用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;
答案 1 :(得分:2)
您可以使用递归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)
修改强>
您可以更新CTE以实现此目的:
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)
修改强>
对于较大的数据集,您需要添加maxrecursion
查询提示;我编辑了之前的查询以显示此信息。来自联机丛书:
指定此查询允许的最大递归数。 number是0到32767之间的非负整数。当0为时 指定,不应用限制。
在这种情况下,我将其设置为0
,即不限制递归。
答案 2 :(得分:0)
我实际上最终得到了以下内容。它在半小时内完成了所有300万行。
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