2

これは、同じ名前の他の質問の複製ではありません。これよりも良い名前が思い浮かびませんでした。

Player という名前の SQL テーブルと、Unit という名前の別の SQL テーブルがあります。

  • 各プレーヤーは、外部キーの UnitID を介してチームに属している必要があります。
  • 各ユニットは、再帰フィールド ParentUnitID を介して別のチームに属することができます。
  • ParentUnit は ParentUnit (無限再帰) になることができますが、プレイヤーは 1 つのチームにしか所属できません。
  • ユニットは多くの子を持つことができます

だからそれは(トップダウン)...

  • TeamA (最上位)
  • チームB(所属^^)
  • TeamC(所属^^)
  • TeamD(所属^^)
  • Player_1 (所属 ^^)

私の質問は、プレイヤーの PlayerID (そのテーブルの PK) が与えられた場合、特定のチームを取得するための最良の方法は何ですか?

データ、構造、およびクエリについては、私の SQLFiddle を参照してください: http://sqlfiddle.com/#!3/78965/3

私のデータ(フィドルから)では、「TeamB」の下にすべてのプレーヤーを取得できるようにしたいのですが、「Player4」のトップユニットは「TeamC」である必要があります。そのために渡す必要があるのは、PlayerID と「TeamB」の ID だけです。つまり、「TeamB の下にあるすべてのプレーヤーとトップ ユニットを取得し、Player4 以外のすべてのプレーヤーを除外します。

編集:上記の段落は次のように読むべきだ と思います:(フィドルからの)データを使用して、「TeamB」の下でプレーするトップチームを確立できるようにしたいと考えています。「TeamB」の下のトップチームごとに、そのチーム以下でプレーするすべてのプレーヤーを確立したいと考えています。次に、プレーヤーのリストを 1 人以上の特定のプレーヤーに制限する機能が必要です。

SQLFiddle でわかるように、プレイヤーごとに複数の行が返されます。これは簡単な修正だと思いますが、理解できません...それが私のフィドルで目指していることですが、まあ、ええと、少し面倒です... :)

編集:詳細情報:

OK、これがストアド プロシージャであると想像してみてください。

  • PlayerID 1,2,3,4 を渡します
  • UnitID 2 を渡します

返されるデータは次のようになると思います

Player3, TeamC

TeamB (ID 2) の子孫である唯一のプレーヤーであるため、Player3 のみが返され、Player3 が属する最高レベルのユニット (UnitID 2 の下) であるため、TeamC が返されます。

代わりに渡した場合:

  • PlayerID 1,2,3,4 を渡します
  • UnitID 6 を渡します

私は期待するだろう

Player1, Team2
Player2, Team2
4

2 に答える 2

2

この回答は完全に書き直されました。オリジナルはすべての状況でうまく機能しなかった

CTE を変更して、すべてのユニットの完全なユニット階層を可能なルート (最上位ユニット) として表す必要がありました。これにより、ユニットごとに複数の子を持つ真の階層が可能になります。

このSQL Fiddleのサンプル データを拡張して、ユニット 11 と 12 の両方にプレーヤーが割り当てられるようにしました。ユニット 1 の下のあるレベルでユニットのためにプレーする 3 人のプレーヤーのそれぞれについて、正しい行を適切に返します。

「ルート」ユニット ID とプレーヤー ID のリストは、一番外側の WHERE 句の一番下にあるので、必要に応じて ID を簡単に変更できます。

with UnitCTE as (
  select u.UnitID,
         u.Designation UnitDesignation,
         u.ParentUnitID as ParentUnitID,
         p.Designation as ParentUnitDesignation,
         u.UnitID TopUnitID,
         u.Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit u
    left outer join Unit p
      on u.ParentUnitId = p.UnitID
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID as ParentUnitID,
         c.UnitDesignation as ParentUnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t1.*
  from UnitCTE t1
  join UnitCTE t2
    on t2.TopUnitID = t1.UnitID
   and t2.TopUnitID = t1.TopUnitID
  join Player p
    on p.UnitID = t2.UnitID
 where t1.ParentUnitID = 1
   and playerID in (1,2,3,4,5,6)

これは、CTE に組み込まれたユニット ID 基準を持つ、わずかに最適化されたバージョンです。CTE は、親 ID が選択されたユニット ID (この場合は 1) であるユニットをルートとする階層のみを計算します。

with UnitCTE as (
  select u.UnitID,
         u.Designation UnitDesignation,
         u.ParentUnitID as ParentUnitID,
         p.Designation as ParentUnitDesignation,
         u.UnitID TopUnitID,
         u.Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit u
    left outer join Unit p
      on u.ParentUnitId = p.UnitID
   where u.ParentUnitID = 1
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID as ParentUnitID,
         c.UnitDesignation as ParentUnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t1.*
  from UnitCTE t1
  join UnitCTE t2
    on t2.TopUnitID = t1.UnitID
  join Player p
    on p.UnitID = t2.UnitID
 where playerID in (1,2,3,4,5,6)



これが私の元の答えです。 ユニット階層が、ユニットごとに 1 つの子のみを許可するように制約されている場合にのみ機能します。質問の SQL Fiddle の例には、ユニット 1 の 3 つの子があるため、ユニット 1 に対して実行すると、プレイヤー 3、5、および 6 の複数の行が誤って返されます。

これは、問題を示すSQL Fiddleです。

with UnitCTE as
  select UnitID,
         Designation UnitDesignation,
         ParentUnitID as ParentUnitID,
         cast(null as varchar(50)) as ParentUnitDesignation,
         UnitID TopUnitID,
         Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit
   where ParentUnitID is null
  union all
  select t.UnitID,
         t.Designation UnitDesignation,
         c.UnitID,
         c.UnitDesignation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
)
select p.PlayerID,
       p.Designation,
       t2.*
  from Player p
  join UnitCTE t1
    on p.UnitID = t1.UnitID
  join UnitCTE t2
    on t2.TopUnitID = t1.TopUnitID
   and t1.TeamLevel >= t2.TeamLevel
  join UnitCTE t3
    on t3.TopUnitID = t1.TopUnitID
   and t2.TeamLevel = t3.TeamLevel+1
 where t3.UnitID = 2
   and playerID in (1,2,3,4)
于 2012-07-16T22:41:09.343 に答える
2
with UnitCTE as (
  select UnitID,
         Designation,
         ParentUnitID as ParentUnitID,
         cast(null as varchar(50)) as ParentUnitDesignation,
         UnitID TopUnitID,
         Designation TopUnitDesignation,
         1 as TeamLevel
    from Unit
   where ParentUnitID is null
  union all
  select t.UnitID,
         t.Designation,
         c.UnitID,
         c.Designation,
         c.TopUnitID,
         c.TopUnitDesignation,
         TeamLevel+1 as TeamLevel
    from Unit t
    join UnitCTE c
      on t.ParentUnitID = c.UnitID
      --WHERE t.UnitID = 1
),
x AS (
select Player.PlayerID,
       pDesignation = Player.Designation, t1.*,
       rn = ROW_NUMBER() OVER (PARTITION BY Player.PlayerID ORDER BY Player.Designation)
  from Player
  join UnitCTE t1
    on Player.UnitID = t1.UnitID
  join UnitCTE t2
    on t1.TopUnitID = t2.TopUnitID
   and t2.TeamLevel=2
)
SELECT * FROM x
WHERE rn = 1
   ORDER BY TeamLevel
于 2012-07-16T21:36:09.483 に答える