Sql server SQL Server CTE-查找每个子ID的顶级父ID?
我有一个包含层次结构数据的表-类似于:Sql server SQL Server CTE-查找每个子ID的顶级父ID?,sql-server,sql-server-2008,tsql,common-table-expression,Sql Server,Sql Server 2008,Tsql,Common Table Expression,我有一个包含层次结构数据的表-类似于: childID | parentID ____________________ 1 | 5 5 | 9 9 | 20 2 | 4 3 | 7 7 | 8 8 | 8 20 | 20 4 | 4 8 | 8 ;WITH cte AS (
childID | parentID
____________________
1 | 5
5 | 9
9 | 20
2 | 4
3 | 7
7 | 8
8 | 8
20 | 20
4 | 4
8 | 8
;WITH cte AS (
SELECT a.childID
,a.parentID
,1 AS lvl
FROM [Agent_Agents] a
WHERE a.childID = 214 //<==== value to begin with !! - thats part the problem
UNION ALL
SELECT tmp.childID
,tmp.parentID
,cte.lvl+1
FROM [Agent_Agents] tmp
INNER JOIN cte ON tmp.childID = cte.parentID
WHERE cte.childID<>cte.parentID
)
SELECT *
FROM cte
WHERE lvl = (
SELECT MAX(lvl)
FROM cte
)
select * from myTable Cross Apply (
;WITH cte AS (....)
)
期望输出:
我已经创建了一个递归CTE,它发现我是顶级父ID
比如:
childID | parentID
____________________
1 | 5
5 | 9
9 | 20
2 | 4
3 | 7
7 | 8
8 | 8
20 | 20
4 | 4
8 | 8
;WITH cte AS (
SELECT a.childID
,a.parentID
,1 AS lvl
FROM [Agent_Agents] a
WHERE a.childID = 214 //<==== value to begin with !! - thats part the problem
UNION ALL
SELECT tmp.childID
,tmp.parentID
,cte.lvl+1
FROM [Agent_Agents] tmp
INNER JOIN cte ON tmp.childID = cte.parentID
WHERE cte.childID<>cte.parentID
)
SELECT *
FROM cte
WHERE lvl = (
SELECT MAX(lvl)
FROM cte
)
select * from myTable Cross Apply (
;WITH cte AS (....)
)
但是我从我的测试中得到了什么这是不可能的
我们知道,将递归CTE放入UDF的另一个想法会对UDF的性能造成影响
如何创建此查询以使其实际工作?还是某种近似的解决方案
这是我试过的
你不能这样做吗
;WITH cte AS (....)
SELECT
*
FROM
cte
CROSS APPLY
dbo.myTable tbl ON cte.XXX = tbl.XXX
将交叉应用放在CTE定义之后-放回引用CTE的一条SQL语句中。那不管用吗
或者:-翻转您的逻辑-执行自上而下的CTE,首先选择顶级节点,然后在层次结构中迭代。通过这种方式,您可以在递归CTE的第一部分中轻松确定顶级父级-如下所示:
;WITH ChildParent AS
(
SELECT
ID,
ParentID = ISNULL(ParentID, -1),
SomeName,
PLevel = 1, -- defines level, 1 = TOP, 2 = immediate child nodes etc.
TopLevelFather = ID -- define "top-level" parent node
FROM dbo.[Agent_Agents]
WHERE ParentID IS NULL
UNION ALL
SELECT
a.ID,
ParentID = ISNULL(a.ParentID, -1),
a.SomeName,
PLevel = cp.PLevel + 1,
cp.TopLevelFather -- keep selecting the same value for all child nodes
FROM dbo.[Agent_Agents] a
INNER JOIN ChildParent cp ON r.ParentID = cp.ID
)
SELECT
ID,
ParentID,
SomeName,
PLevel,
TopLevelFather
FROM ChildParent
根据示例数据,这将为您提供类似的节点,稍微扩展:
ID ParentID SomeName PLevel TopLevelFather
20 -1 Top#20 1 20
4 -1 TOP#4 1 4
8 -1 TOP#8 1 8
7 8 ChildID = 7 2 8
3 7 ChildID = 3 3 8
2 4 ChildID = 2 2 4
9 20 ChildID = 9 2 20
5 9 ChildID = 5 3 20
1 5 ChildID = 1 4 20
现在,如果您从这个CTE输出中选择一个特定的子节点,您将始终获得所需的所有信息,包括子节点的级别及其顶级父节点。我还没有时间进一步研究您的问题,不确定我是否理解您的问题,但是你不能用这个svf来获取顶级父亲的身份证吗
CREATE FUNCTION [dbo].[getTopParent] (
@ChildID INT
)
RETURNS int
AS
BEGIN
DECLARE @result int;
DECLARE @ParentID int;
SET @ParentID=(
SELECT ParentID FROM ChildParent
WHERE ChildID = @ChildID
)
IF(@ParentID IS NULL)
SET @result = @ChildID
ELSE
SET @result = [dbo].[getTopParent](@ParentID)
RETURN @result
END
然后,您应该能够通过以下方式找到每个顶级父级:
SELECT ChildID
, [dbo].[getTopParent](ChildID) AS TopParentID
FROM ChildParent
我不知道你在找什么,但可能是这个
;WITH c
AS (SELECT childid,
parentid,
parentid AS topParentID
FROM @myTable
WHERE childid = parentid
UNION ALL
SELECT T.childid,
T.parentid,
c.topparentid
FROM @myTable AS T
INNER JOIN c
ON T.parentid = c.childid
WHERE T.childid <> T.parentid)
SELECT childid,
topparentid
FROM c
ORDER BY childid
这与by相同,不同之处在于我使用了表变量,并且对于根节点,您有childID=parentID,而marc_s的答案对于根节点,parent_ID=null。在我看来,对于根节点,最好使用parent_ID=null
select distinct
a.ChildID,a.ParentID,
--isnull(nullif(c.parentID,b.parentID),a.parentID) as toppa,
B.parentID
--,c.parentID
,isnull(nullif(d.parentID,a.parentID),c.parentID) as toppa1,a.name
from myTable a
inner join myTable c
on a.parentID=c.parentID
inner join myTable b
on b.childID=a.parentID
inner join myTable d
on d.childID=b.parentID
我使用了不带CTE的表达式,然后使用联接来获取子级的步骤到步骤父级,然后在SQL Server 2005中引入了更重要的公共表表达式,而不是在Server 2000中,因此使用联接来获取值这是获取子级值的parentid的基本方法
With cte as
(
Select ChileId,Name,ParentId from tblHerarchy
where ParentId is null
union ALL
Select h.ChileId,h.Name,h.ParentId from cte
inner join tblHerarchy h on h.ParentId=cte.ChileId
)
Select * from cte
考虑此示例数据和相应的SQL,以访问子记录及其顶级父记录 SQL代码:
;WITH c AS (
SELECT Id, Name, ParentId as CategoryId,
Id as MainCategoryId, Name AS MainCategory
FROM pmsItemCategory
WHERE ParentId is null
UNION ALL
SELECT T.Id, T.Name, T.ParentId, MainCategoryId, MainCategory
FROM pmsItemCategory AS T
INNER JOIN c ON T.ParentId = c.Id
WHERE T.ParentId is not null
)
SELECT Id, Name, CategoryId, MainCategoryId, MainCategory
FROM c
order by Id
我不认为它会成功-因为CTE知道如何执行和找到一个!!ID的顶级父项。请注意214值。。。。。我如何发送Foreach ID=>Cte.DoWorkForID?@RoyiNamir:有了这个ChildParent Cte,你就不能从ChildParent中选择*ID=214并得到你需要的吗?谢谢你的回答。提姆。我们知道的问题是udf在内联调用时会降低性能。。。这就是为什么我倾向于避免这种解决方案。通常的问题是:我有一个id为且parentId为的表。foreach行中的select*from…-我需要另一个具有最高父值的列。-我尝试了Cross Aply-vut递归引擎CTE不能与Cross Apply一起使用。我为所需输出添加了一个打印屏幕。我为所需输出添加了一个打印屏幕。@RoyiNamir-我对SE数据的查询返回您想要的结果。我刚刚添加了name和parentID列。我很高兴听到你为什么决定从最上面的开始,而不是从叶子开始。。。。这里的逻辑是什么,尽管它起作用了?为什么我们不能从最上面的叶子开始?@RoyiNamir从叶子节点开始,将向结果集中添加比您需要的更多的行。如果一个父项有三个子项,则该父项将在结果集中出现三次。在递归查询中,从上到下只为每个节点添加一次找到的新节点。您说:如果一个父节点有三个子节点,则该父节点将在结果集中出现三次-但根据我的问题,您应该看到三次。否?如果1有父2,5有父2,9有父2–您应该看到1,2和5,2和9,2。。。。否?请解释您的答案,而不是仅仅给出itI。我使用不带CTE的表达式,然后使用联接来获取子级的步骤到步骤父级,然后在SQL Server 2005中引入了更重要的公共表表达式,而不是在Server 2000中,因此使用联接来获取值这是获取子级值的parentid的基本方法解决方案不能回答问题。原始数据在ParentID中不包含NULL。建议的查询不会产生所需的输出。