sql >> Database teknologi >  >> RDS >> Sqlserver

Begrænsning af rekursion til et bestemt niveau - Dublerede rækker

Dette svar er blevet fuldstændig omskrevet. Originalen virkede ikke helt under alle omstændigheder

Jeg var nødt til at ændre CTE for at repræsentere det fulde enhedshierarki for hver enhed som en mulig rod (øverste enhed). Det tillader et ægte hierarki med flere børn pr. enhed.

Jeg har udvidet eksempeldataene i denne SQL-violinator at have en spiller tildelt til både enhed 11 og 12. Det returnerer korrekt den korrekte række for hver af 3 spillere, der spiller for en enhed på et niveau under enhed 1.

"Root" enheds-id'et og listen over spiller-id'er er bekvemt i den yderste WHERE-klausul nederst, hvilket gør det nemt at ændre ID'erne efter behov.

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)

Her er en let optimeret version, der har Unit ID-kriterierne indlejret i CTE. CTE'en beregner kun hierarkier forankret på enheder, hvor forældre-id er det valgte enheds-id (1 i dette tilfælde)

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)


Her er mit originale svar. Det virker kun, hvis enhedshierarkiet er begrænset til kun at tillade ét barn pr. enhed. SQL Fiddle-eksemplet i spørgsmålet har 3 børn til enhed 1, så det returnerer fejlagtigt flere rækker for spillere 3, 5 og 6, hvis det køres mod enhed 1

Her er en SQL violin der viser problemet.

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. Sådan udskrives en MySQL-databasetabel i PHP ved hjælp af PDO

  2. MySQL:Deltag i forespørgsel på tværs af flere databaser placeret på forskellige servere

  3. MySQL Query får de sidste N rækker pr. gruppe

  4. Mysql lagrede funktioner og gruppevis min