2016-04-22 11 views
5

Sto attraversando un momento difficile con questo. Ho visto alcuni esempi su come ottenere tutti i record figlio da una tabella autoreferenziale fornita a un genitore e persino come ottenere i genitori dei record figli.Seleziona tutto il livello di gerarchia e sotto SQL Server

Quello che sto cercando di fare è restituire un record e tutti i record figlio dati l'ID.

Per mettere questo in un contesto - Ho una gerarchia aziendale. Dove:

#Role  Level# 
-------------------- 
Corporate   0 
Region   1 
District   2 
Rep    3 

cosa ho bisogno è una procedura che (1) capisce che livello il record è e (2) recupera che i record di registrazione e di tutti i bambini.

L'idea di essere una Regione può vedere tutti i distretti e rappresentanti in un distretto, i Distretti possono vedere i loro rappresentanti. I rappresentanti possono solo vedere se stessi.

Ho tavolo:

ID   ParentId   Name 
------------------------------------------------------- 
1    Null    Corporate HQ 
2    1     South Region 
3    1     North Region 
4    1     East Region 
5    1     West Region 
6    3     Chicago District 
7    3     Milwaukee District 
8    3     Minneapolis District 
9    6     Gold Coast Dealer 
10   6     Blue Island Dealer 

Come faccio a fare questo:

CREATE PROCEDURE GetPositions 
    @id int 
AS 
BEGIN 
    --What is the most efficient way to do this-- 
END 
GO 

Ad esempio, il risultato atteso per @id = 3, vorrei tornare:

3, 6, 7, 8, 9, 10 

Apprezzerei qualsiasi aiuto o idee su questo.

+1

Quale sarebbe il risultato previsto? –

+0

Ho aggiornato la domanda per mostrare il risultato previsto. – JDBennett

risposta

6

Si potrebbe fare questo attraverso una CTE ricorsiva:

DECLARE @id INT = 3; 

WITH rCTE AS(
    SELECT *, 0 AS Level FROM tbl WHERE Id = @id 
    UNION ALL 
    SELECT t.*, r.Level + 1 AS Level 
    FROM tbl t 
    INNER JOIN rCTE r 
     ON t.ParentId = r.ID 
) 
SELECT * FROM rCTE OPTION(MAXRECURSION 0); 

ONLINE DEMO

+0

È perfetto! Solo per curiosità - questo si comporterà bene contro un grande volume di dischi. Cioè Diciamo che ho record 50K + e l'Id è il genitore aziendale (in alto). Come reagirà? – JDBennett

+0

Generalmente, il CTE ricorsivo non si adatta bene ai tavoli di grandi dimensioni. Come con tutto, prova !! –

0

Supponendo che sei su una versione ragionevolmente moderna di SQL Server, è possibile utilizzare il tipo di dati hierarchyid con un po ' un po 'di grasso di gomito. In primo luogo, il programma di installazione:

alter table [dbo].[yourTable] add [path] hierarchyid null; 

Successivamente, sarà popolare la nuova colonna:

with cte as (
    select *, cast(concat('/', ID, '/') as varchar(max)) as [path] 
    from [dbo].[yourTable] 
    where [ParentID] is null 

    union all 

    select child.*, 
     cast(concat(parent.path, child.ID, '/') as varchar(max)) as [path] 
    from [dbo].[yourTable] as child 
    join cte as parent 
     on child.ParentID = parent.ID 
) 
update t 
set path = c.path 
from [dbo].[yourTable] as t 
join cte as c 
    on t.ID = c.ID; 

Questo è solo uno standard di un'espressione di tabella ricorsiva palude con una colonna calcolata che rappresenta la gerarchia. Questa è la parte difficile. Ora, il procedimento può essere simile a questa:

create procedure dbo.GetPositions (@id int) as 
begin 
    declare @h hierarchyid 
    set @h = (select Path from [dbo].[yourTable] where ID = @id); 

    select ID, ParentID, Name 
    from [dbo].[yourTable] 
    where Path.IsDescendentOf(@h) = 1; 
end 

Quindi, per concludere, tutto quello che stai facendo con il hierarchyid è la memorizzazione il lignaggio per una data riga in modo che non si deve calcolare su la mosca al momento scelto.

Problemi correlati