Come si ottiene l'ultimo record generato in un CTE ricorsivo?
-
09-06-2019 - |
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.
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.