2008-08-29 6 views
1

In dem folgenden Code verwende ich einen rekursiven CTE (allgemeiner Tabellenausdruck) in SQL Server 2005, um zu versuchen, den übergeordnete übergeordneten Ebene einer grundlegenden hierarchischen Struktur zu finden. Die Regel dieser Hierarchie besteht darin, dass jede CustID eine ParentID hat und wenn die CustID kein Parent hat, dann die ParentID = CustID und es die höchste Ebene ist.Wie erhalten Sie den letzten Datensatz in einem rekursiven CTE generiert?

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 
) 

Also, wenn tblCustomer sieht wie folgt aus:

ParentID CustID 
5   5 
1   8 
5   4 
4   1 

Das Ergebnis, das ich aus dem Code erhalten oben ist:

ParentID CustID 
4   1 
5   4 
5   5 

Was ich will, nur die letzte Zeile dieses Ergebnisses ist:

ParentID CustID 
5   5 

Wie d o Ich gebe nur den letzten im CTE generierten Datensatz zurück (was die höchste CustID-Ebene wäre)?

Beachten Sie auch, dass es mehrere unabhängige CustID-Hierarchien in dieser Tabelle gibt, so dass ich nicht einfach eine SELECT * FROM tblCustomer WHERE ParentID = CustID tun kann. Ich kann nicht nach ParentID oder CustID sortieren, da die ID-Nummer nicht mit der Position in der Hierarchie verknüpft ist.

Antwort

2

Wenn Sie nur die höchste Rekursionstiefe wollen, können Sie nicht so etwas tun? Wenn Sie dann tatsächlich den CTE abfragen, suchen Sie einfach nach der Zeile mit max (Depth)? Wie 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 Anpassung, was trevor schlägt vor, dies könnte mit dem gleichen CTE verwendet werden:

select top 1 * from CTELevelone order by Depth desc 

Ich glaube nicht, dass CustomerID war unbedingt das, was man in dem Fall bestellen, indem Sie wollte Du hast es beschrieben, aber ich war auch nicht ganz klar in der Frage.

1

Ich bin nicht sicher, ob ich das Problem vollständig zu verstehen, aber nur & slash es hacken Sie könnten versuchen:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC 

Das setzt voraus, dass die CustID ist auch, wie im Beispiel in Ordnung, und nicht etwas wie eine GUID.

0

Zuerst wird die CTE nicht beendet, wenn eines der Elternteile gleich ist. Da es sich um einen rekursiven CTE handelt, muss er beendet werden. Mit parent und cust id selbe wird die Schleife nicht enden.

Msg 530, Ebene 16, Status 1, Zeile 15 Die Anweisung wurde beendet. Die maximale Rekursion 100 wurde vor dem Abschluss der Anweisung erschöpft.