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.

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top