2014-04-22 17 views
6

Ho una tabella SQL di base con una semplice connessione heirarchial tra ogni riga. Quello è che esiste un ParentID per ogni riga e che usa la sua connessione con un'altra riga. La sua come segueQuery per elencare tutti i genitori gerarchici e fratelli e i loro figli, ma non i propri elenchi dei bambini

AccountID | AccountName | ParentID 
--------------------------------------- 
    1   Mathew  0 
    2   Philip  1 
    3   John   2 
    4   Susan   2 
    5   Anita   1 
    6   Aimy   1 
    7   Elsa   3 
    8   Anna   7 
    ............................. 
................................. 
    45   Kristoff  8 

Speranza la struttura è chiaro

Ma la mia esigenza di listng questi è un po 'strano. Quello è quando passiamo un AccountID, dovrebbe elencare tutti i relativi genitori e fratelli germani e fratelli. Ma non elenca mai alcun figlio di tale ID account a nessun livello. Posso spiegarlo in modo un po 'più dettagliato con un'immagine. Ci scusiamo per la chiarezza del quadro .. il mio è un vecchio telefono di cam .. enter image description here

Quando passiamo l'AccountID 4, si dovrebbe elencare tutti i genitori ei suoi fratelli, ma non dovrebbe elencare 4,6 , 7,8,9,10. Ciò significa che l'account e tutti i bambini dovrebbero essere evitati nel risultato (in base agli elementi dell'albero immagine). Spero che la spiegazione sia chiara.

+1

Qualora si mostrano anche 5,11, 12, ... - tavolo intero senza 4,6,7,8,9,10? O solo genitori di 4 - 2,1? – valex

+0

@valex Sì .. esattamente .. questo ho citato come i suoi fratelli e i loro figli insieme a tutti i suoi genitori .. –

risposta

7

Se ho capito bene e bisogna uscita intera tabella, tranne 4 e tutti del suo discendenti allora Prova questa ricerca ricorsiva:

WITH CT AS 
(
    SELECT * FROM T WHERE AccountID=4 
    UNION ALL 
    SELECT T.* FROM T 
    JOIN CT ON T.ParentID = CT.AccountId 
) 
SELECT * FROM T WHERE AccountID 
       NOT IN (SELECT AccountID FROM CT) 

SQLFiddle demo

Rispondendo alla domanda di il commento:

Quindi non attraverserà verso l'alto. Attraversa solo l'account specificato . Per esempio se passo 4 come primo parametro e 2 come secondo parametro , il risultato dovrebbe essere questi valori 2,5,11,12

Si dovrebbe iniziare dal ID = 2 e viaggiare a fondo escludere ID = 4 in modo da tagliare tutto il sottostruttura dopo ID = 4:

WITH CT AS 
(
    SELECT * FROM T WHERE AccountID=2 
    UNION ALL 
    SELECT T.* FROM T 
    JOIN CT ON T.ParentID = CT.AccountId 
    WHERE T.AccountId<>4 
) 

SELECT * FROM CT 
+0

Quello è l'uomo perfetto !!! evviva .. questo è esattamente quello che stavo cercando .. –

+0

Scusa .. ho bisogno di un po 'più di supporto se non ti dispiace. Come possiamo modificare la query in modo che non salga da un secondo parametro. Quindi non attraverserà la cima. Attraversa solo l'account specificato. Per esempio se passo 4 come primo parametro e 2 come secondo parametro, il risultato dovrebbe essere questi valori 2,5,11,12 –

+1

@sforsandeep Ho aggiornato la mia risposta per risolvere questo. – valex

2

Prova questo:

;with cte as 
(select accountid,parentid, 0 as level from tbl 
where parentid = 0 
union all 
select t.accountid,t.parentid,(level+1) from 
cte c inner join tbl t on c.accountid= t.parentid 
) 
select * from cte 
where level < (select level from cte where accountid = @accountid) 

Quando si passa nel parametro @accountid Ciò restituirà i valori accountid di tutti i nodi sui livelli prima di quella del parametro.

Se si desidera riportare tutto sullo stesso livello dell'input tranne l'input stesso, è possibile modificare la clausola where in;

where level <=(select level from cte where accountid= @accountid) 
and accountid <> @accountid 

Nel tuo esempio, se @accountid = 4, questo restituirà i valori 1,2,3 (antenati) e 5,13,14 (fratelli).

1

Questo restituisce ciò che si desidera?

declare @AccountID int 
set @AccountID = 4 

;with parents 
as (

    select AccountID, AccountName, ParentID 
    from Account 
    where AccountID = (select ParentID from Account Where AccountID = @AccountID) 

    union all 

    select A.AccountID, A.AccountName, A.ParentID 
    from Account as A 
    join parents as P 
     on P.ParentID = A.AccountID 
    ), 
children 
as (
    select AccountID, AccountName, ParentID 
    from parents 

    union all 

    select A.AccountID, A.AccountName, A.ParentID 
    from Account as A 
    join children as C 
     on C.AccountID = A.ParentID 
    where A.AccountID <> @AccountID 
    ) 
select distinct AccountID, AccountName, ParentID 
from children 
order by AccountID 
1

Per me sembra che tu voglia salire sull'albero.Quindi, considerando questo test dati

DECLARE @tbl TABLE(AccountID INT,AccountName VARCHAR(100),ParentID INT) 
INSERT INTO @tbl 
VALUES 
(1,'Mathew',0), 
(2,'Philip',1), 
(3,'John',2), 
(4,'Susan',2), 
(5,'Anita',1), 
(6,'Aimy',1), 
(7,'Elsa',3), 
(8,'Anna',7) 

L'avrei scritto una query come questa:

DECLARE @AcountID INT=4 

;WITH CTE 
AS 
(
    SELECT 
     tbl.AccountID, 
     tbl.AccountName, 
     tbl.ParentID 
    FROM 
     @tbl AS tbl 
    WHERE 
     [email protected] 
    UNION ALL 
    SELECT 
     tbl.AccountID, 
     tbl.AccountName, 
     tbl.ParentID 
    FROM 
     @tbl AS tbl 
    JOIN CTE 
     ON CTE.ParentID=tbl.AccountID 
) 
SELECT 
    * 
FROM 
    CTE 
WHERE 
    NOT [email protected] 

Ciò restituirà un risultato come questo:

2 Philip 1 
1 Mathew 0 
Problemi correlati