Como você obtém o último registro gerado em um CTE recursivo?
-
09-06-2019 - |
Pergunta
No código abaixo, estou usando um CTE (Common Table Expression) recursivo no SQL Server 2005 para tentar encontrar o pai de nível superior de uma estrutura hierárquica básica.A regra desta hierarquia é que todo CustID possui um ParentID e se o CustID não tiver pai, então ParentID = CustID e é o nível mais 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
)
Então, se tblCustomer estiver assim:
ParentID CustID
5 5
1 8
5 4
4 1
O resultado que obtenho do código acima é:
ParentID CustID
4 1
5 4
5 5
O que eu quero é apenas a última linha desse resultado:
ParentID CustID
5 5
Como faço para retornar apenas o último registro gerado no CTE (que seria o CustID de nível mais alto)?
Observe também que existem várias hierarquias CustID não relacionadas nesta tabela, portanto não posso simplesmente fazer um SELECT * FROM tblCustomer WHERE ParentID = CustID.Não consigo fazer o pedido por ParentID ou CustID porque o número de ID não está relacionado ao local onde está na hierarquia.
Solução
Se você deseja apenas a maior profundidade de recursão, não poderia fazer algo assim? Então, quando você realmente consultar o CTE, basta procurar a linha com max (Profundidade)?Igual a:
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)
ou, adaptando o que Trevor sugere, poderia ser usado com o mesmo CTE:
select top 1 * from CTELevelone order by Depth desc
Não acho que CustomerID fosse necessariamente o que você queria solicitar no caso que descreveu, mas também não fui perfeitamente claro sobre a questão.
Outras dicas
Não tenho certeza se entendi completamente o problema, mas apenas para hackear e cortá-lo, você pode tentar:
SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC
Isso pressupõe que o CustID também esteja em ordem como no exemplo, e não algo como um GUID.
Primeiro, o cte não será concluído se algum dos pais-filhos for igual.Como é um CTE recursivo, ele deve ser encerrado.Tendo Parent e cust id iguais, o loop não terminará.
MSG 530, Nível 16, Estado 1, Linha 15 A declaração terminou.A recursão máxima 100 foi esgotada antes da conclusão da instrução.