如何使用SQL Server 2008 hierarchyid获取节点的所有祖先?

mar*_*her 26 sql-server hierarchyid

给定一个带有hierarchyid类型列的表,如何编写查询以返回特定节点的祖先的所有行?

有一个IsDescendantOf()功能,非常适合孩子们,但没有相应的IsAncestorOf()功能来返回祖先(并且缺少一个GetAncestors()功能似乎是一个疏忽.)

mar*_*c_s 31

最常用的方法是递归公用表表达式(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
Run Code Online (Sandbox Code Playgroud)

(改编自Simon Ince博客文章)

Simon Ince还提出了第二种方法,他只是基本上颠倒了条件 - 而不是检测那些作为目标人的祖先的人条目,他转过来检查:

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
Run Code Online (Sandbox Code Playgroud)

这将从您的表中选择所有行,您感兴趣的目标人员是层次结构中任何级别的后代.因此,这将发现目标人的直接和非直接祖先一直到根.

  • 在那篇博文中,不是这个CTE解决方案然后是一个更简单的解决方案("这工作正常,但它是实现它的最佳方式吗?不.请再试一次!")? (5认同)
  • 我知道这已经很老了,但我为未来的读者写了这篇文章:当执行计划不存在时,“Simon Ince 博客文章”中的方法比“CTE”方法慢近 100 倍。 (2认同)

Ric*_*ard 15

以下是一个选择的答案:

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
Run Code Online (Sandbox Code Playgroud)