Wie erhält man den letzten Datensatz, der in einem rekursiven CTE generiert wird?
-
09-06-2019 - |
Frage
Im folgenden Code verwende ich einen rekursiven CTE (Common Table Expression) in SQL Server 2005, um zu versuchen, das übergeordnete Element der obersten Ebene einer grundlegenden hierarchischen Struktur zu finden.Die Regel dieser Hierarchie besteht darin, dass jede CustID eine ParentID hat und wenn die CustID kein übergeordnetes Element hat, dann ist ParentID = CustID und es handelt sich um die höchste Ebene.
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
)
Wenn tblCustomer also so aussieht:
ParentID CustID
5 5
1 8
5 4
4 1
Das Ergebnis, das ich aus dem obigen Code erhalte, ist:
ParentID CustID
4 1
5 4
5 5
Was ich möchte, ist nur die letzte Zeile dieses Ergebnisses:
ParentID CustID
5 5
Wie kann ich einfach den letzten im CTE generierten Datensatz zurückgeben (das wäre die CustID der höchsten Ebene)?
Beachten Sie auch, dass es in dieser Tabelle mehrere unabhängige CustID-Hierarchien gibt, sodass ich nicht einfach ein SELECT * FROM tblCustomer WHERE ParentID = CustID ausführen kann.Ich kann nicht nach ParentID oder CustID bestellen, da die ID-Nummer nichts mit der Position in der Hierarchie zu tun hat.
Lösung
Wenn Sie nur die höchste Rekursionstiefe wünschen, könnten Sie dann nicht so etwas tun? Wenn Sie dann tatsächlich den CTE abfragen, suchen Sie einfach nach der Zeile mit max(Depth)?Etwa so:
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)
oder, um zu adaptieren, was Trevor vorschlägt, könnte dies mit demselben CTE verwendet werden:
select top 1 * from CTELevelone order by Depth desc
Ich glaube nicht, dass CustomerID in dem von Ihnen beschriebenen Fall unbedingt das war, was Sie bestellen wollten, aber ich war mir bei der Frage auch nicht ganz klar.
Andere Tipps
Ich bin mir nicht sicher, ob ich das Problem vollständig verstehe, aber um es einfach in den Griff zu bekommen, könnten Sie Folgendes versuchen:
SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC
Das setzt voraus, dass die CustID auch wie im Beispiel in Ordnung ist und nicht so etwas wie eine GUID.
Erstens wird der CTE nicht abgeschlossen, wenn eines der übergeordneten und untergeordneten Elemente identisch ist.Da es sich um einen rekursiven CTE handelt, muss er beendet werden.Wenn die Eltern- und Kunden-ID identisch sind, wird die Schleife nicht beendet.
MSG 530, Stufe 16, Zustand 1, Zeile 15 Die Erklärung endete.Die maximale Rekursion von 100 wurde vor Abschluss der Anweisung ausgeschöpft.