Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Membatasi rekursi ke level tertentu - Baris duplikat

Jawaban ini telah ditulis ulang sepenuhnya. Versi asli tidak cukup berfungsi dalam semua keadaan

Saya harus mengubah CTE untuk mewakili hierarki Unit lengkap untuk setiap Unit sebagai kemungkinan root (unit teratas). Ini memungkinkan hierarki sejati dengan banyak anak per Unit.

Saya memperluas data sampel dalam SQL Fiddle ini untuk memiliki pemain yang ditugaskan ke unit 11 dan 12. Ini mengembalikan baris yang benar untuk masing-masing dari 3 pemain yang bermain untuk Unit pada tingkat tertentu di bawah Unit 1.

ID Unit "root" dan daftar ID pemain berada di klausa WHERE terluar di bagian bawah, sehingga memudahkan untuk mengubah ID sesuai kebutuhan.

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)

Berikut adalah versi yang sedikit dioptimalkan yang memiliki kriteria ID Unit yang disematkan di CTE. CTE hanya menghitung hierarki yang berakar pada Unit di mana ID Induk adalah ID Unit yang dipilih (1 dalam kasus ini)

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)


Inilah jawaban asli saya. Ini hanya berfungsi jika Hierarki Unit dibatasi untuk mengizinkan hanya satu anak per Unit. Contoh SQL Fiddle dalam pertanyaan memiliki 3 anak untuk Unit 1, jadi itu mengembalikan beberapa baris untuk Pemain 3, 5 dan 6 jika dijalankan melawan Unit 1

Ini adalah SQL Fiddle yang menunjukkan masalahnya.

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. Mengatasi SQL Server Database Terjebak dalam Masalah Mode Tersangka Secara Efisien

  2. Prosesor Intel Xeon yang Dapat Diskalakan dan SQL Server 2017

  3. Apakah mungkin untuk memaksa penguncian tingkat baris di SQL Server?

  4. WITH (NOLOCK) vs SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

  5. Bagaimana cara memantau perintah t-sql saja di SQL Profiler?