我有一个像这个100, 110, 120, 130
这样的父ID列表,它们是动态的,可以更改。我希望在一组中获得指定父项的所有后代。为了让单亲的孩子,我使用了这样的查询:
WITH parent AS (
SELECT PersonHierarchyID FROM PersonHierarchy
WHERE PersonID = 100
)
SELECT * FROM PersonHierarchy
WHERE PersonHierarchyID.IsDescendantOf((SELECT * FROM parent)) = 1
不知道如何为多个父母做这件事。我的第一次尝试是写几个工会,但我确信应该有更明智的方法。
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数组作为参数的查询,并将所有后代返回到一个集合中。
答案 0 :(得分:13)
你太在意了。
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。让我们谈谈这个功能一秒钟。实质上,它表示&#34;对于传入的hierarchyId,获取当前级别。然后调用GetAncestor,直到您处于层次结构的顶部。&#34;。请注意,它可选地返回传入的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>)
它可能适用于您,也可能不适合您。试试看吧!
答案 1 :(得分:1)
对某人可能有用。我通过自加入查询找到了这样做的方法:
SELECT p2.* FROM PersonHierarchy p1
LEFT JOIN PersonHierarchy p2
ON p2.PersonHierarchyID.IsDescendantOf(p1.PersonHierarchyID) = 1
WHERE
p1.PersonID IN (100, 110, 120, 130)
答案 2 :(得分:0)
请检查,这应该适合你。我还没有尝试修改你的脚本,只是把查询放在循环中。希望它有所帮助。
DECLARE @String VARCHAR(MAX) = '100, 110, 120, 130'
DECLARE @SQL VARCHAR(MAX)
SET @String = REPLACE(@String, CHAR(32), '') + ','
WHILE CHARINDEX(',', @String) > 0
BEGIN
DECLARE @ToString INT
DECLARE @StringLength INT
DECLARE @WorkingString VARCHAR(MAX)
DECLARE @WorkingLength INT
SET @ToString = CHARINDEX(',', @String)
SET @StringLength = LEN(@String)
SET @WorkingString = SUBSTRING(@String, 1, @ToString - 1)
SET @String = SUBSTRING(@String, @ToString + 1, @StringLength)
SET @WorkingString = 'SELECT * FROM PersonHierarchy ' + CHAR(13) + CHAR(10)
+ 'WHERE PersonHierarchyID.IsDescendantOf((SELECT PersonHierarchyID FROM PersonHierarchy WHERE PersonID = '
+ @WorkingString + ')) = 1' + CHAR(13) + CHAR(10)
+ CASE WHEN CHARINDEX(',', @String) > 0 THEN 'UNION ALL'+ CHAR(13) + CHAR(10) ELSE '' END
SET @SQL = ISNULL(@SQL,'') + @WorkingString
END
PRINT @SQL
EXEC (@SQL)
答案 3 :(得分:0)
您可以使用此查询
Select
child.*,
child.[PersonHierarchyID].GetLevel(),
child.[PersonHierarchyID].GetAncestor(1)
From
PersonHierarchy as parents
Inner Join PersonHierarchy as child
On child.[PersonHierarchyID].IsDescendantOf(parents.[PersonHierarchyID] ) = 1
Where
parents.[PersonHierarchyID] = 0x68