sql >> Databáze >  >> RDS >> Sqlserver

Omezení rekurze na určitou úroveň - Duplicitní řádky

Tato odpověď byla kompletně přepsána. Originál se tak úplně nepovedl za všech okolností

Musel jsem změnit CTE, aby reprezentoval úplnou hierarchii jednotek pro každou jednotku jako možný kořen (horní jednotka). Umožňuje skutečnou hierarchii s více dětmi na jednotku.

Rozšířil jsem ukázková data v tomto SQL Fiddle mít hráče přiřazeného k oběma jednotkám 11 a 12. Správně vrátí správný řádek pro každého ze 3 hráčů, kteří hrají za jednotku na určité úrovni pod jednotkou 1.

ID "kořenové" jednotky a seznam ID hráčů je pohodlně v nejvzdálenější klauzuli WHERE ve spodní části, což usnadňuje změnu ID podle potřeby.

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)

Zde je mírně optimalizovaná verze, která má kritéria Unit ID vložená do CTE. CTE počítá pouze hierarchie založené na jednotkách, kde rodičovské ID je zvolené ID jednotky (v tomto případě 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)


Zde je moje původní odpověď. Funguje pouze v případě, že je hierarchie jednotek omezena tak, aby povolovala pouze jednoho potomka na jednotku. Příklad SQL Fiddle v otázce má 3 potomky pro Unit 1, takže falešně vrací více řádků pro hráče 3, 5 a 6, pokud běží proti Unit 1

Zde je SQL Fiddle to demonstruje problém.

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. implodování seznamu pro použití v klauzuli python MySQLDB IN

  2. Příkaz SQL pro zobrazení čísla ve slovech bez použití jakékoli přímé funkce (oracle)

  3. Knihovně místností pro Android se nepodařilo zkopírovat databázi z podkladu

  4. Rychlejší levé JOIN nebo rychlejší vnitřní spojení?