2010-06-25 53 views
24

給定一個帶有hierarchyid類型列的表,如何編寫查詢以返回作爲特定節點的祖先的所有行?如何獲得使用SQL Server 2008 hierarchyid的節點的所有祖先?

有一個IsDescendantOf()功能,這是完美的讓孩子,但沒有相應IsAncestorOf()函數返回的祖先(和缺乏GetAncestors()功能恍如很大的一個疏忽。)

+9

是不是'child.IsDescendantOf(父)'一樣'parent.IsAncestorOf(孩子)'? – Gabe 2010-06-25 17:18:24

回答

24

最常用的方法是一個遞歸公用表表達式(CTE)

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 

(改編自Simon Ince blog post

西蒙·因斯也建議他基本上只是反轉條件的第二種方法 - 而不是檢測是目標的人的祖先,那些人的條目,他轉身檢查:

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 

這將選擇所有從表中的行,你感興趣的目標人是下一級的任何級別的後代。所以這會發現目標人的直接和非直接的祖先一直到根。

+5

在這篇博文中,是不是這個CTE解決方案接着是一個更簡單的解決方案(「這工作正常,但它是實現它的最佳方式?不,再試一次!」)? – AakashM 2010-06-25 17:07:44

+0

@AakashM:是的,還有第二種選擇,事實上 - 我可能不會使用這個選項,但它也可以起作用。 – 2010-06-25 17:12:08

+0

我知道這是非常古老的,但我爲未來的讀者撰寫這篇文章:當執行計劃不存在時,「Simon Ince博客文章」中的方法比「CTE」方法慢100倍。 – Achilles 2017-04-20 13:36:35

12

這裏有一個答案卷起成一個單一的選擇:

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

where子句的第一個謂詞是多餘的,因爲父類始終是它自己的後代。 http://msdn.microsoft.com/en-us/library/bb677203(v=sql.105).aspx – influent 2014-12-17 17:53:59

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

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

即使您在hierarchyID上有一個索引,它也必須爲每一行評估IsDesendentOf,否?我想我有更好的辦法(看我的回答) – 2016-02-14 01:48:22

0

我寫了一個擴展值HIERARCHYID成其組成祖先用戶定義的表值函數。然後可以將輸出重新連接到hierarchyid列以專門獲取這些祖先。

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 

去了解使用它:

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

請幫我解決這個問題。 http://stackoverflow.com/questions/44016261/how-do-you-get-recursivelevel-using-sql-server-2012-hierarchyid – ManojKanth 2017-05-17 05:36:44

相關問題