Как вы получаете всех предков узла, используя SQL Server 2008ierarchyid? - PullRequest
25 голосов
/ 25 июня 2010

Учитывая таблицу со столбцом типа hierarchyid, как написать запрос для возврата всех строк, которые являются предками определенного узла?

Существует функция IsDescendantOf(), которая идеально подходит для получения детей, но нет соответствующей функции IsAncestorOf() для возврата предков (а отсутствие функции GetAncestors() выглядит как упущение).

Ответы [ 4 ]

30 голосов
/ 25 июня 2010

Наиболее часто используемый подход - это рекурсивное выражение общих таблиц (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 )

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

Это выберет все строки изваша таблица, где целевой человек, которого вы интересуете, является потомком любого уровня иерархии.Таким образом, вы обнаружите, что непосредственные и не непосредственные предки этого целевого человека вплоть до самого корня.

14 голосов
/ 03 августа 2011

Вот ответ, свернутый в один выбор:

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
3 голосов
/ 22 января 2014
Declare @hid hierarchyid=0x5D10 -- Child hierarchy id

SELECT
*
FROM 
  dbo.TableName
WHERE 
  @hid.IsDescendantOf(ParentHierarchyId) = 1
1 голос
/ 14 февраля 2016

Я написал определяемую пользователем табличную функцию, которая расширяет значение иерархии до составляющих его предков.Затем выходные данные могут быть присоединены обратно к столбцу иерархии, чтобы получить этих предков специально.

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
...