Cette réponse a été complètement réécrite. L'original n'a pas tout à fait fonctionné dans toutes les circonstances
J'ai dû changer le CTE pour représenter la hiérarchie complète des unités pour chaque unité en tant que racine possible (unité supérieure). Il permet une véritable hiérarchie avec plusieurs enfants par Unité.
J'ai étendu les exemples de données dans ce SQL Fiddle pour avoir un joueur affecté aux deux unités 11 et 12. Il renvoie correctement la ligne correcte pour chacun des 3 joueurs qui jouent pour une unité à un certain niveau en dessous de l'unité 1.
L'ID d'unité "racine" et la liste des ID de joueur se trouvent commodément dans la clause WHERE la plus à l'extérieur en bas, ce qui facilite la modification des ID selon les besoins.
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)
Voici une version légèrement optimisée qui intègre les critères d'identification d'unité dans le CTE. Le CTE ne calcule que les hiérarchies enracinées dans les unités où l'ID parent est l'ID d'unité choisi (1 dans ce cas)
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)
Voici ma réponse originale. Cela ne fonctionne que si la hiérarchie des unités est contrainte de n'autoriser qu'un seul enfant par unité. L'exemple SQL Fiddle dans la question a 3 enfants pour l'unité 1, il renvoie donc à tort plusieurs lignes pour les joueurs 3, 5 et 6 s'il est exécuté contre l'unité 1
Voici un SQL Fiddle qui illustre le problème.
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)