2010-06-25 2 views
24

Wenn Sie eine Tabelle mit einer hierarchyid-Spalte angeben, wie schreiben Sie eine Abfrage, um alle Zeilen zurückzugeben, die Vorfahren eines bestimmten Knotens sind?Wie erhalten Sie alle Vorfahren eines Knotens mit SQL Server 2008 hierarchyid?

Es gibt eine IsDescendantOf()-Funktion, die für immer die Kinder perfekt ist, aber es gibt keine entsprechenden IsAncestorOf() Funktion Vorfahren zurückzukehren (und das Fehlen einer GetAncestors() Funktion durchaus ein Versehen scheint, wie.)

+9

Ist das nicht 'child.IsDescendantOf (Eltern)' die gleichen wie 'parent.IsAncestorOf (Kind)'? – Gabe

Antwort

24

Die am häufigsten verwendete Ansatz würde

WITH Ancestors(Id, [Name], AncestorId) AS 
(
     SELECT 
      Id, [Name], Id.GetAncestor(1) 
     FROM 
      dbo.HierarchyTable 
     WHERE 
      Name = 'Joe Blow' -- or whatever you need to select that node 

     UNION ALL 

     SELECT 
      ht.Id, ht.[Name], ht.Id.GetAncestor(1) 
     FROM 
      dbo.HierarchyTable ht 
     INNER JOIN 
      Ancestors a ON ht.Id = a.AncestorId 
) 
SELECT *, Id.ToString() FROM Ancestors 

(angepasst von einem Simon Ince blog post)

Simon Ince auch einen rekursiven allgemeinen Tabellenausdruck (CTE) sein schlägt einen zweiten Ansatz, bei dem er den Zustand im Grunde nur umkehrt - anstatt diese Person Einträge des Erfassens, dass ein Vorfahre der Zielperson sind, er den Scheck dreht sich um:

DECLARE @person hierarchyid 

SELECT @person = Id 
FROM dbo.HierachyTable 
WHERE [Name] = 'Joe Blow'; 

SELECT 
    Id, Id.ToString() AS [Path], 
    Id.GetLevel() AS [Level], 
    Id.GetAncestor(1), 
    Name 
FROM 
    dbo.HierarchyTable 
WHERE 
    @person.IsDescendantOf(Id) = 1 

Dadurch werden alle Zeilen aus einer Tabelle auswählen, wo die Zielperson, an der Sie interessiert sind, ein Nachkomme von - irgendeiner Ebene in der Hierarchie ist. So werden die direkten und nicht-unmittelbaren Vorfahren der Zielperson bis zur Wurzel gefunden.

+5

In diesem Blogpost, ist diese CTE-Lösung dann nicht gefolgt von einem einfacheren ("Das funktioniert gut, aber ist es der optimale Weg, um es zu erreichen? Nein. Versuchen wir es noch einmal!")? – AakashM

+0

@AakashM: Ja, es gibt eine zweite Option, in der Tat - nicht eine, die ich wahrscheinlich verwenden würde, aber es wird auch funktionieren, von den Blicken davon. –

+0

Ich weiß, das ist sehr alt, aber ich schreibe dies für zukünftige Leser: Die Methode von "Simon Ince Blog Post" ist fast 100 mal langsamer als die "CTE" -Methode, wenn der Ausführungsplan nicht existiert. – Achilles

12

Hier ist eine Antwort in einem einzigen gerollt wählen:

SELECT t1.Id.ToString() as Path, t1.Name 
    FROM (SELECT * FROM HierarchyTable 
     WHERE Name = 'Joe Blow') t2, 
    HierarchyTable t1 
    WHERE t2.Id.IsDescendantOf(t1.Id) = 1 
+0

Das erste Prädikat der WHERE-Klausel ist redundant, da ein Elternteil immer ein Nachkomme von sich selbst ist. http://msdn.microsoft.com/en-us/library/bb677203(v=sql.105).aspx – influent

2
Declare @hid hierarchyid=0x5D10 -- Child hierarchy id 

SELECT 
* 
FROM 
    dbo.TableName 
WHERE 
    @hid.IsDescendantOf(ParentHierarchyId) = 1 
+0

Auch wenn Sie einen Index für die Hierarchie-ID haben, muss IsDesententOf für jede Zeile ausgewertet werden, nein? Ich denke, ich habe einen besseren Weg (siehe meine Antwort) –

0

Ich schrieb eine benutzerdefinierte Tabellenfunktion, die einen hierarchyid Wert in seiner konstituierenden Vorfahren erweitert. Die Ausgabe kann dann wieder in die Hierarchie-Spalte eingefügt werden, um diese Vorfahren spezifisch zu erhalten.

alter function dbo.GetAllAncestors(@h hierarchyid, @ReturnSelf bit) 
returns table 
as return 
select @h.GetAncestor(n.Number) as h 
from dbo.Numbers as n 
where n.Number <= @h.GetLevel() 
    or (@ReturnSelf = 1 and n.Number = 0) 

union all 

select @h 
where @ReturnSelf = 1 
go 

gehen darüber mit:

select child.ID, parent.ID 
from dbo.yourTable as child 
cross apply dbo.GetAllAncestors(child.hid, 1) as a 
join dbo.yourTable as parent 
    on parent.hid = a.h 
+0

bitte helfen Sie mir, dieses Problem zu lösen. http://stackoverflow.com/questions/44016261/how-do-you-get-recursivelevel-using-sql-server-2012-hierarchyid – ManojKanth

Verwandte Themen