Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Ograniczenie rekurencji do pewnego poziomu - Zduplikowane wiersze

Ta odpowiedź została całkowicie przepisana. Oryginał nie działał we wszystkich okolicznościach

Musiałem zmienić CTE, aby reprezentować pełną hierarchię Jednostek dla każdej Jednostki jako możliwy korzeń (jednostka górna). Pozwala na prawdziwą hierarchię z wieloma dziećmi na jednostkę.

Rozszerzyłem przykładowe dane w tym SQL Fiddle mieć gracza przypisanego do obu jednostek 11 i 12. Prawidłowo zwraca prawidłowy rząd dla każdego z 3 graczy, którzy grają w Jednostkę na pewnym poziomie poniżej Jednostki 1.

Identyfikator jednostki „root” i lista identyfikatorów graczy są wygodnie umieszczone w zewnętrznej klauzuli WHERE na dole, co ułatwia zmianę identyfikatorów w razie potrzeby.

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)

Oto nieco zoptymalizowana wersja, która ma wbudowane kryteria identyfikatora jednostki w CTE. CTE oblicza tylko hierarchie zakorzenione w jednostkach, w których identyfikator nadrzędny jest wybranym identyfikatorem jednostki (w tym przypadku 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)


Oto moja oryginalna odpowiedź. Działa tylko wtedy, gdy Hierarchia Jednostek jest ograniczona do zezwalania tylko na jedno dziecko na Jednostkę. Przykład SQL Fiddle w pytaniu ma 3 dzieci w jednostce 1, więc błędnie zwraca wiele wierszy dla graczy 3, 5 i 6, jeśli zostanie uruchomiony w jednostce 1

Oto SQL Fiddle to pokazuje problem.

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak mogę się dowiedzieć, czy zgłoszono wyjątek SQL z powodu naruszenia klucza obcego?

  2. Jak wstawić do zmiennej tabeli z dynamicznym zapytaniem?

  3. Jak utworzyć tabelę w SQL Server

  4. SQL Server 2008 Wydajność w kolumnie geograficznej z wartościami null z indeksem przestrzennym

  5. Jak utworzyć tabelę tymczasową z typu?