HierarchyID:获取父项列表的所有后代

And*_*ren 9 t-sql sql-server hierarchyid

我有一个像这样的父ID列表,100, 110, 120, 130它是动态的,可以改变.我希望在一组中获得指定父项的所有后代.为了获得单亲的孩子,我使用了这样的查询:

WITH parent AS (
    SELECT PersonHierarchyID FROM PersonHierarchy
    WHERE PersonID = 100    
)
SELECT * FROM PersonHierarchy
WHERE PersonHierarchyID.IsDescendantOf((SELECT * FROM parent)) = 1
Run Code Online (Sandbox Code Playgroud)

不知道如何为多个父母这样做.我的第一次尝试是写几个工会的东西,但我确信应该有更聪明的方法来做到这一点.

SELECT * FROM PersonHierarchy 
WHERE PersonHierarchyID.IsDescendantOf(
    (SELECT PersonHierarchyID FROM PersonHierarchy WHERE PersonID = 100)
) = 1
UNION ALL
SELECT * FROM PersonHierarchy 
WHERE PersonHierarchyID.IsDescendantOf(
    (SELECT PersonHierarchyID FROM PersonHierarchy WHERE PersonID = 110)
) = 1
UNION ALL ...
Run Code Online (Sandbox Code Playgroud)

PS我也发现这样的查询来选择可能有用的ID列表:

SELECT * FROM (VALUES (100), (110), (120), (130)) AS Parent(ParentID)
Run Code Online (Sandbox Code Playgroud)

总而言之,我的目标是编写一个接受父ID数组作为参数的查询,并将所有后代返回到一个集合中.

Ben*_*hul 15

你的想法太难了.

WITH parent AS (
    SELECT PersonHierarchyID FROM PersonHierarchy
    WHERE PersonID in (<list of parents>)    
)
SELECT * FROM PersonHierarchy
WHERE PersonHierarchyID.IsDescendantOf((SELECT * FROM parent)) = 1
Run Code Online (Sandbox Code Playgroud)

不过我会这样写的:

select child.*
from PersonHierarchy as parent
inner join PersonHierarchy as child
   on child.PersonHierarchyID.IsDescendantOf(
       parent.PersonHierarchyId
   ) = 1
where Parent.PersonId in (<list of parents>)
Run Code Online (Sandbox Code Playgroud)

注意:在这两种情况下,这可能会很慢,因为它必须为n*m个条目评估IsDescendantOf(其中n是父项列表的基数,m是表的基数).

我最近有一个类似的问题,我通过编写一个表值函数来解决它,给定一个hierarchyId将返回所有父项.让我们看一下使用这种方法解决问题的方法.一,功能:

CREATE FUNCTION [dbo].[GetAllAncestors] (@h HierarchyId, @IncludeSelf bit)
RETURNS TABLE
AS RETURN

    WITH cte AS (
        SELECT @h AS h, 1 AS IncludeSelf
    )
    SELECT @h.GetAncestor(n.NumberId) AS Hierarchy
    FROM ref.Number AS n
    WHERE n.NumberId <= @h.GetLevel()
    AND n.NumberId >= 1

    UNION ALL

    SELECT h
    FROM cte
    WHERE IncludeSelf = @IncludeSelf
Run Code Online (Sandbox Code Playgroud)

它假定您有一个Numbers表.它们非常有用.如果您没有,请在此处查看已接受的答案.让我们来谈谈这个功能.从本质上讲,它表示"对于传入的hierarchyId,获取当前级别.然后调用GetAncestor直到您处于层次结构的顶部." 请注意,它可选地返回传入的hierarchyId.在我的情况下,我想考虑一个记录本身的祖先.你可能想要也可能不想做.

转到使用它的解决方案,我们得到类似的东西:

select child.*
from PersonHierarchy as child
cross apply [dbo].[GetAllAncestors](child.PersonHierarchyId, 0) as ancestors
inner join PersonHierarchy as parent
  on parent.PersonHierarchyId = ancestors.Hierarchy
where parent.PersonId in (<list of parents>)
Run Code Online (Sandbox Code Playgroud)

它可能适用于您,也可能不适合您.试试看吧!


And*_*ren 5

它可能对某人有用。我找到了通过自连接查询来做到这一点的方法:

SELECT p2.* FROM PersonHierarchy p1
LEFT JOIN PersonHierarchy p2 
    ON p2.PersonHierarchyID.IsDescendantOf(p1.PersonHierarchyID) = 1
WHERE 
    p1.PersonID IN (100, 110, 120, 130)
Run Code Online (Sandbox Code Playgroud)