2008-08-29 12 views
1

Dans le code ci-dessous J'utilise un CTE récursive (Common Table Expression) dans SQL Server 2005 pour essayer de trouver le parent de haut niveau d'une structure hiérarchique de base. La règle de cette hiérarchie est que chaque CustID a ParentID et si le CustID n'a pas de parent alors le ParentID = CustID et il est le plus haut niveau.Comment obtenez-vous le dernier enregistrement généré dans un CTE récursive?

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 
) 

Donc, si tblCustomer ressemble à ceci:

ParentID CustID 
5   5 
1   8 
5   4 
4   1 

Le résultat que je reçois du code ci-dessus est la suivante:

ParentID CustID 
4   1 
5   4 
5   5 

Ce que je veux est juste la dernière ligne de ce résultat:

ParentID CustID 
5   5 

Comment d o Je viens de retourner le dernier enregistrement généré dans le CTE (qui serait le plus haut niveau CustID)?

Notez également qu'il existe plusieurs hiérarchies CustID non liées dans cette table, donc je ne peux pas simplement faire un SELECT * FROM tblCustomer WHERE ParentID = CustID. Je ne peux pas commander par ParentID ou CustID parce que le numéro d'identification n'est pas lié à l'endroit où il se trouve dans la hiérarchie.

Répondre

2

Si vous voulez juste voulez la meilleure profondeur de récursivité vous ne pourriez pas faire quelque chose comme ça? Alors, lorsque vous interrogez réellement le CTE il suffit de regarder pour la ligne avec max (profondeur)? Comme si:

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, en adaptant ce trevor suggère, cela pourrait être utilisé avec le même CTE:

select top 1 * from CTELevelone order by Depth desc 

Je ne pense pas nécessairement CustomerID était ce que vous vouliez commander par dans le cas vous avez décrit, mais je n'étais pas parfaitement clair sur la question non plus.

1

Je ne suis pas certain que je comprends très bien le problème, mais juste pour pirater & slash à ce que vous pouvez essayer:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC 

Cela suppose que le CustID est aussi pour que dans l'exemple, et non quelque chose comme un GUID.

0

D'abord la cte ne sera pas terminé si l'un des parents et enfants sont les mêmes. Comme il s'agit d'un CTE récursif, il doit être terminé. Ayant Parent et cust id même, la boucle ne se terminera pas.

Msg 530, niveau 16, état 1, ligne 15 La déclaration terminée. La récursivité maximale 100 a été épuisée avant la fin de l'instruction.