我有一个包含层次结构数据的表 - 类似于:
childID | parentID
____________________
1 | 5
5 | 9
9 | 20
2 | 4
3 | 7
7 | 8
8 | 8
20 | 20
4 | 4
8 | 8
期望的输出:
我创建了一个递归CTE,它找到了顶部fatherID
。
类似的东西:
;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
)
问题:
我用显式 childID
值执行CTE以开始(214)!
所以它只给我214的价值。
CTE执行递归部分并找到childID的topParent。
但
我希望ForEach row in the Table
- 使用childID
值执行CTE!
我尝试使用CROSS APPLY
:
类似的东西:
select * from myTable Cross Apply (
;WITH cte AS (....)
)
但恕我直言(来自我的测试!!) - 这是不可能的。
将递归CTE放入UDF的另一个想法是性能损失(我们知道udf的问题)。
如何创建此查询以使其真正起作用? (或一些接近解决方案)?
这是我尝试过的事情
https://data.stackexchange.com/stackoverflow/query/edit/69458
答案 0 :(得分:20)
你不能做这样的事吗?
;WITH cte AS (....)
SELECT
*
FROM
cte
CROSS APPLY
dbo.myTable tbl ON cte.XXX = tbl.XXX
将CTE定义后的CROSS APPLY
放在一个引用回CTE的SQL语句中。那不行吗?
OR: - 翻转你的逻辑 - 做一个“自上而下”的CTE,首先选择顶级节点,然后遍历hiearchy。这样,您可以轻松确定递归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输出中选择一个特定的子节点,您将始终获得所需的所有信息 - 包括子级的“级别”及其顶级父节点。
答案 1 :(得分:15)
不确定我理解你在寻找什么,但可能就是这样。
;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
与answer的marc_s相同,不同之处在于我使用了您的表变量,并且您对根节点有childID = parentID
这一事实,其中marc_s的答案为{{} 1}}用于根节点。在我看来,最好为根节点parent_ID = null
。
答案 2 :(得分:1)
我还没有时间深入研究你的问题而且我不确定我是否理解你的问题,但是你不能用这个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
答案 3 :(得分:0)
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中而不是在服务器2000中引入的,所以使用连接来获取值这是基本方式为了得到一个儿童价值的parentid
答案 4 :(得分:0)
https://plnkr.co/edit/gGCiYjcq70xaewn3n22F?p=preview
select dbo.[fn_getIMCatPath](8)
select Cat_id,Cat_name,dbo.[fn_getIMCatPath](cat_id) from im_category_master
Create FUNCTION [dbo].[fn_getIMCatPath] (@ID INT)
returns NVARCHAR(1000)
AS
BEGIN
DECLARE @Return NVARCHAR(1000),
@parentID INT,
@iCount INT
SET @iCount = 0
SELECT @Return = Cat_name,
@parentID = parent_id
FROM im_category_master
WHERE [cat_id] = @ID
WHILE @parentID IS NOT NULL
BEGIN
SELECT @Return = cat_name + '>' + @Return,
@parentID = parent_id
FROM im_category_master
WHERE [cat_id] = @parentID
SET @iCount = @iCount + 1
IF @parentID = -1
BEGIN
SET @parentID = NULL
END
IF @iCount > 10
BEGIN
SET @parentID = NULL
SET @Return = ''
END
END
RETURN @Return
END
答案 5 :(得分:0)
考虑此示例数据和相应的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
答案 6 :(得分:-1)
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
答案 7 :(得分:-1)
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
答案 8 :(得分:-1)
With cteherarchy 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 cteherarchy