2012-08-24 10 views
9

Nel server SQLTSQL - Il ciclo while è selezionato?

Ok, quindi sto lavorando con una tabella di database in cui le righe possono avere righe padre, che possono quindi avere righe padre proprie. Devo selezionare la 'riga' di root. Non conosco il modo migliore per farlo.

C'è un campo chiamato ParentId, che collega la riga alla riga con quell'ID. Quando ParentId = 0, è la riga radice.

Questa è la mia domanda ora:

SELECT Releases.Name,WorkLog.WorkLogId 

FROM WorkLog,Releases 
WHERE 
Releases.ReleaseId = WorkLog.ReleaseId 
and WorkLogDateTime >= @StartDate 
and WorkLogDateTime <= @end 

non si ha realmente bisogno il nome del rilascio dei bambini uscite, voglio solo la radice Nome Release, quindi voglio selezionare il risultato di un ciclo While come questo:

WHILE (ParentReleaseId != 0) 
BEGIN 
@ReleaseId = ParentReleaseId 
END 

Select Release.Name 
where Release.RealeaseId = @ReleaseId 

so che la sintassi è orribile, ma si spera che vi sto dando un'idea di quello che sto cercando di acheive.

+1

quindi immagino ci sia più di una release con 'ParentReleaseId' pari a zero? – AakashM

+0

Stai dicendo che la tabella delle versioni è gerarchica, ad esempio la Release X ha un predecessore, e quindi quella versione ha il suo predecessore, e così via? Quindi il problema è trovare la versione * originale * per ogni * rilascio * successivo che si verifica entro le date specificate? –

+0

Spero che tu sia nel 2005 o più tardi, puoi confermare? –

risposta

9

Ecco un esempio, che potrebbe essere utile:

Questa query è sempre un elemento inferiore di un albero, e la ricerca fino al genitore dei genitori. Come se avessi 4 livelli nel mio tavolo -> categoria 7-> 5, 5-> 3, 3-> 1. Se lo do al 5 troverà il 1, perché questo è il livello più alto dei tre.

(Cambiando il last scegli si può avere tutti i genitori sulla strada.)

DECLARE @ID int 

SET @ID = 5; 

WITH CTE_Table_1 
(
    ID, 
    Name, 
    ParentID 
) 
AS(
    SELECT 
    ID, 
    Name, 
    ParentID 
    FROM Table_1 
    WHERE ID = @ID 

UNION ALL 

SELECT 
    T.ID, 
    T.Name, 
    T.ParentID 
FROM Table_1 T 
INNER JOIN CTE_Table_1 ON CTE_Table_1.ParentID = T.ID 
) 

SELECT * FROM CTE_Table_1 WHERE ParentID = 0 
+0

DARN, mi ha battuto con il CTE. Buon lavoro :) –

+0

Grazie, sto usando questi "algoritmi" molto in questa settimana :) –

+0

Funzionerà per un numero indefinito di livelli? –

1

qualcosa di simile

with cte as 
(
    select id,parent_id from t where [email protected] 
    union all 
    select t.id,t.parent_id 
    from cte 
    join t on cte.parent_id = t.id where cte.parent_id<>0 
) 
select * 
from cte 
join t on cte.id=t.id where cte.parent_id = 0 

e con il violino: http://sqlfiddle.com/#!3/a5fa1/1/0

+0

Penso che il membro di ancoraggio del CTE dovrà fare i conti con i limiti di date della query di esempio dell'OP, vero? –

+0

Da quello che ho capito il valore iniziale è stato selezionato in precedenza, e il vincolo della data sarà su quella selezione. –

0

Utilizzando Andras approccio, ho modificato la selezione finale per darmi direttamente l'ID della root release

WITH cte_Releases 
( 
    ReleaseId, 
    ParentReleaseID 
) 
AS( 
    SELECT 
    ReleaseId, 
    ParentReleaseID 
    FROM Releases 
    Where ReleaseId = 905 

UNION ALL 

SELECT 
    R.ReleaseId, 
    R.ParentReleaseID 
FROM Releases R 
INNER JOIN cte_Releases ON cte_Releases.ParentReleaseID = R.ReleaseId 
) 

SELECT max(ReleaseId) as ReleaseId, min(ReleaseId) as RootReleaseId FROM cte_Releases 

mio problema ora è che voglio correre attraverso tutti @IDs (905 in quel codice) e unire ogni record ad un risultato