sql >> Database >  >> RDS >> Sqlserver

Recursie beperken tot een bepaald niveau - Dubbele rijen

Dit antwoord is volledig herschreven. Het origineel werkte niet helemaal onder alle omstandigheden

Ik moest de CTE wijzigen om de volledige eenheidshiërarchie voor elke eenheid weer te geven als een mogelijke root (topeenheid). Het maakt een echte hiërarchie mogelijk met meerdere kinderen per eenheid.

Ik heb de voorbeeldgegevens uitgebreid in deze SQL Fiddle om een ​​speler toegewezen te krijgen aan beide eenheden 11 en 12. Het geeft de juiste rij terug voor elk van de 3 spelers die voor een eenheid spelen op een bepaald niveau onder eenheid 1.

De "root" Unit-ID en de lijst met speler-ID's staan ​​handig in de buitenste WHERE-clausule onderaan, waardoor het gemakkelijk is om de ID's indien nodig te wijzigen.

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)

Hier is een enigszins geoptimaliseerde versie waarin de Unit ID-criteria zijn ingebed in de CTE. De CTE berekent alleen hiërarchieën die zijn geworteld in Units waarbij Parent ID de gekozen Unit ID is (1 in dit geval)

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)


Hier is mijn oorspronkelijke antwoord. Het werkt alleen als de eenheidshiërarchie beperkt is tot het toestaan ​​van slechts één kind per eenheid. Het SQL Fiddle-voorbeeld in de vraag heeft 3 onderliggende items voor Unit 1, dus het retourneert ten onrechte meerdere rijen voor Spelers 3, 5 en 6 als deze wordt uitgevoerd tegen Unit 1

Hier is een SQL Fiddle dat toont het probleem aan.

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)


  1. Laravel en AWS Cloudfront

  2. PostgreSQL:ST_GeomFromText(onbekend) bestaat niet

  3. Lijst van alle tijdelijke tabellen in SQLite

  4. PDO/MYSQL voorbereide statements zonder escapetekens?