Comment obtenir le dernier enregistrement généré dans un CTE récursif ?
-
09-06-2019 - |
Question
Dans le code ci-dessous, j'utilise un CTE (Common Table Expression) récursif dans SQL Server 2005 pour essayer de trouver le parent de niveau supérieur d'une structure hiérarchique de base.La règle de cette hiérarchie est que chaque CustID a un ParentID et si le CustID n'a pas de parent alors ParentID = CustID et c'est le niveau le plus élevé.
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 j'obtiens du code ci-dessus est :
ParentID CustID
4 1
5 4
5 5
Ce que je veux, c'est juste la dernière ligne de ce résultat :
ParentID CustID
5 5
Comment puis-je simplement renvoyer le dernier enregistrement généré dans le CTE (qui serait le CustID de niveau le plus élevé) ?
Notez également qu'il existe plusieurs hiérarchies CustID non liées dans ce tableau, je ne peux donc pas simplement faire un SELECT * FROM tblCustomer WHERE ParentID = CustID.Je ne peux pas commander par ParentID ou CustID car le numéro d'identification n'est pas lié à son emplacement dans la hiérarchie.
La solution
Si vous voulez juste la profondeur de récursion la plus élevée, ne pourriez-vous pas faire quelque chose comme ça ? Ensuite, lorsque vous interrogez réellement le CTE, recherchez simplement la ligne avec max(Depth) ?Ainsi:
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 que suggère Trevor, cela pourrait être utilisé avec le même CTE :
select top 1 * from CTELevelone order by Depth desc
Je ne pense pas que CustomerID soit nécessairement ce que vous vouliez commander dans le cas que vous avez décrit, mais je n'étais pas non plus parfaitement clair sur la question.
Autres conseils
Je ne suis pas sûr de bien comprendre le problème, mais juste pour le pirater, vous pouvez essayer :
SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC
Cela suppose que le CustID est également en ordre comme dans l'exemple, et non quelque chose comme un GUID.
Premièrement, le cte ne sera pas terminé si l'un des parents-enfants est le même.Comme il s'agit d'un CTE récursif, il doit être terminé.Ayant le parent et le client identiques, la boucle ne se terminera pas.
MSG 530, niveau 16, état 1, ligne 15 La déclaration s'est terminée.La récursivité maximale de 100 a été épuisée avant la fin de l'instruction.