この回答は完全に書き直されました。オリジナルはすべての状況でうまく機能しなかった
CTE を変更して、すべてのユニットの完全なユニット階層を可能なルート (最上位ユニット) として表す必要がありました。これにより、ユニットごとに複数の子を持つ真の階層が可能になります。
この SQL Fiddle のサンプル データを拡張しました ユニット 11 と 12 の両方にプレーヤーを割り当てます。ユニット 1 の下のあるレベルのユニットでプレーする 3 人のプレーヤーのそれぞれについて、正しい行を適切に返します。
「ルート」ユニット ID とプレーヤー ID のリストは、必要に応じて ID を簡単に変更できるように、下部の最も外側の WHERE 句にあるので便利です。
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)
プレ>これは、ユニット ID 基準が CTE に埋め込まれた、わずかに最適化されたバージョンです。 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)
プレ>