sql-server - HierarchyID:获取所有后代以获得 parent 列表

标签 sql-server tsql hierarchyid

我有一个像这样的100, 110, 120, 130的父ID列表,它是动态的并且可以更改。我想将指定 parent 的所有后代放在一个集合中。为了让 child 成为单亲 parent ,我使用了以下查询:

WITH parent AS (
    SELECT PersonHierarchyID FROM PersonHierarchy
    WHERE PersonID = 100    
)
SELECT * FROM PersonHierarchy
WHERE PersonHierarchyID.IsDescendantOf((SELECT * FROM parent)) = 1

不知道如何为多个 parent 做这件事。我的第一个尝试是写一些类似的联合体,但是我确信应该有更聪明的方法来这样做。
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 ...

P.S.我也找到了这样的查询来选择ID列表,这可能会有所帮助:
SELECT * FROM (VALUES (100), (110), (120), (130)) AS Parent(ParentID)

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

最佳答案

你想得太辛苦了

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

我会这样写:
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>)

注意:在这两种情况下,这可能会很慢,因为它必须为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

假设您有一个Numbers表。它们非常有用。如果您没有,请查看已接受的答案here。让我们再谈一谈该功能。本质上,它说:“对于传入的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>)

它可能对您不起作用。试试看,看看!

关于sql-server - HierarchyID:获取所有后代以获得 parent 列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25079528/

相关文章:

sql-server - 如何在脚本任务中使用包变量?

sql - 将商或更长的表达式分配给局部(实数)变量 T SQL

sql - 将英国格式日期转换为日期时间

sql - 层次问题

sql - 如何将 SQL 服务器转换为 Oracle?

c# - ASP.NET(C#) 在使用存储过程(sql 数据库)时捕获异常

sql - 替代 DISTINCT 函数

sql-server - 使用 SELECT * 时字段名前面的表名

sql - 如何从 SQL 查询构建对象层次结构? (对于 WPF TreeView )

sql-server - 关于HierarchyId (SQL Server 2008)的一些问题