Domanda

Nel codice seguente utilizzo una CTE ricorsiva (Common Table Expression) in SQL Server 2005 per provare a trovare il genitore di livello superiore di una struttura gerarchica di base.La regola di questa gerarchia è che ogni CustID ha un ParentID e se il CustID non ha un genitore allora ParentID = CustID ed è il livello più alto.

DECLARE @LookupID int

--Our test value
SET @LookupID = 1

WITH cteLevelOne (ParentID, CustID) AS
(
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID
        WHERE c.CustID <> a.CustomerID
)

Quindi, se tblCustomer si presenta così:

ParentID    CustID
5            5
1            8
5            4
4            1

Il risultato che ottengo dal codice sopra è:

ParentID    CustID
4            1
5            4
5            5

Quello che voglio è solo l'ultima riga di quel risultato:

ParentID    CustID
5            5

Come posso semplicemente restituire l'ultimo record generato nel CTE (che sarebbe il CustID di livello più alto)?

Tieni inoltre presente che in questa tabella sono presenti più gerarchie CustID non correlate, quindi non posso semplicemente eseguire un SELECT * FROM tblCustomer WHERE ParentID = CustID.Non posso ordinare per ParentID o CustID perché il numero ID non è correlato alla sua posizione nella gerarchia.

È stato utile?

Soluzione

Se vuoi solo la profondità di ricorsione più alta, non potresti fare qualcosa del genere? Quindi, quando interroghi effettivamente il CTE, cerca semplicemente la riga con max(Depth)?Così:

DECLARE @LookupID int

--Our test value
SET @LookupID = 1;

WITH cteLevelOne (ParentID, CustID, Depth) AS
(
        SELECT   a.ParentID, a.CustID, 1
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID, c.Depth + 1
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID 
        WHERE c.CustID <> a.CustID
)
select * from CTELevelone where Depth = (select max(Depth) from CTELevelone)

oppure, adattando ciò che suggerisce Trevor, questo potrebbe essere usato con lo stesso CTE:

select top 1 * from CTELevelone order by Depth desc

Non penso che CustomerID fosse necessariamente ciò che volevi ordinare nel caso che hai descritto, ma non ero nemmeno perfettamente chiaro sulla domanda.

Altri suggerimenti

Non sono sicuro di comprendere appieno il problema, ma solo per hackerarlo potresti provare:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC

Ciò presuppone che anche il CustID sia in ordine come nell'esempio e non qualcosa come un GUID.

Innanzitutto il CTE non sarà terminato se uno qualsiasi dei figli genitori è lo stesso.Poiché si tratta di una CTE ricorsiva, deve essere terminata.Avendo Parent e cust id uguali, il ciclo non finirà.

MSG 530, Livello 16, Stato 1, linea 15 L'istruzione terminata.La ricorsione massima 100 è stata esaurita prima del completamento dell'istruzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top