28

タイプが列のテーブルがあるhierarchyid場合、特定のノードの祖先であるすべての行を返すクエリをどのように記述しますか?

IsDescendantOf()子を取得するのに最適な関数がありますが、祖先を返すための対応する関数IsAncestorOf()はありません(関数がないことはGetAncestors()かなり見落としのようです)。

4

6 に答える 6

35

最も一般的に使用されるアプローチは、再帰共通テーブル式(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は、基本的に条件を逆にする2番目のアプローチも提案しています。ターゲットの人の祖先である人のエントリを検出する代わりに、チェックを回します。

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

これにより、テーブルからすべての行が選択されます。ここで、関心のあるターゲット人物は、階層の任意のレベルの子孫です。したがって、これにより、対象者の直接および非直接の祖先がルートに至るまで検出されます。

于 2010-06-25T17:00:07.437 に答える
16

これが単一の選択にまとめられた答えです:

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
于 2011-08-03T15:17:47.717 に答える
4
Declare @hid hierarchyid=0x5D10 -- Child hierarchy id

SELECT
*
FROM 
  dbo.TableName
WHERE 
  @hid.IsDescendantOf(ParentHierarchyId) = 1
于 2014-01-22T09:13:31.100 に答える
1

階層ID値をその構成要素の祖先に展開するユーザー定義のテーブル値関数を作成しました。次に、出力を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
于 2016-02-14T01:50:14.357 に答える
0

私がこれまでで最高のものであると私が見つけたベン・トゥイの答えを完成させる...

以下のアプローチでは、1つのクエリで、1つだけでなく、場合によっては複数のリーフ行とそのアセンダントを取得できます。

Create Or Alter Function dbo.GetAllAncestors
(
    @Path       HierarchyId,
    @WithSelf   Bit = 1,
    @MinLevel   Int = 0,
    @MaxLevel   Int = Null
)
Returns Table
As
Return

With Ancestor As
(
    Select  @Path As Path
    Union All

    Select  Path.GetAncestor(1)
    From    Ancestor
    Where   Path.GetLevel() > 0
)

Select  Path, Path.GetLevel() As Level
From    Ancestor
Where   (@WithSelf = 1 Or Path <> @Path)
And     Path.GetLevel() >= Case When @MinLevel < 0 Or @MinLevel Is Null Then 0 Else @MinLevel End
And     (@MaxLevel Is Null Or Path.GetLevel() <= @MaxLevel)

使用するには:

-- This assumes the table has a Path HierarchyId colum, and the values are unique and indexed.

-- If you know the path
Select *
From MyTable
Where Path In
(
    Select Path From dbo.GetAllAncestors(@ThePath, Default, Default, Default)
)

-- If you don't know the path
Select *
From MyTable t1
Where Path In 
(
    Select Path
    From   MyTable t2
           Cross Apply dbo.GetAllAncestors(t2.Path, Default, Default, Default)
    Where  /* Find the leaf record(s) here.
              Note that if multiple rows match, they will all be returned as well as their parents in a single roundtrip. */
)
于 2021-07-24T01:19:54.300 に答える
-1
DECLARE @hid_Specific HIERARCHYID 
SET @hid_Specific = '/1/1/3/1/';

SELECT hrchy_id,* FROM tblHierarchyData 
WHERE PATINDEX(hrchy_id.ToString() + '%', @hid_Specific.ToString()) = 1
于 2020-12-31T06:43:59.830 に答える