2

チームを一連のユーザーに割り当てるクエリが必要です。データは次のようになります。

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 で、新しいチームが開始されます。少なくとも 1 つの A と 1 つの 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' に所属することができます。

4

3 に答える 3

4

まず、各行に増加する番号でラベルを付けることができます。次に、 a を使用し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;

SQL Fiddle の例。

于 2013-02-27T17:46:25.627 に答える
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)

SQL フィドルのデモ

編集:

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)

SQL フィドルのデモ

編集:

maxrecursion大規模なデータセットの場合は、クエリ ヒントを追加する必要があります。これを示すために、以前のクエリを編集しました。Books Online から:

このクエリで許可される再帰の最大数を指定します。number は、0 から 32767 までの負でない整数です。0 を指定すると、制限は適用されません。

この場合、 に設定しました0。つまり、再帰を制限しません。

クエリのヒント

于 2013-02-27T17:46:55.460 に答える
0

私は実際に次のように行きました。300 万以上の行すべてを 30 分で完了しました。

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-03-01T19:46:48.023 に答える