我需要获得给定某个节点的相关节点树,但不是必需的顶级节点。我有一个使用两个CTE的解决方案,因为我正在努力将它全部压缩到一个CTE :)。可能有人有一个时尚的解决方案,以避免使用两个CTE?这是我正在玩的一些代码:
DECLARE @temp AS TABLE (ID INT, ParentID INT)
INSERT INTO @temp
SELECT 1 ID, NULL AS ParentID
UNION ALL
SELECT 2, 1
UNION ALL
SELECT 3, 2
UNION ALL
SELECT 4, 3
UNION ALL
SELECT 5, 4
UNION ALL
SELECT 6, NULL
UNION ALL
SELECT 7, 6
UNION ALL
SELECT 8, 7
DECLARE @startNode INT = 4
;WITH TheTree (ID,ParentID)
AS (
SELECT ID, ParentID
FROM @temp
WHERE ID = @startNode
UNION ALL
SELECT t.id, t.ParentID
FROM @temp t
JOIN TheTree tr ON t.ParentID = tr.ID
)
SELECT * FROM TheTree
;WITH Up(ID,ParentID)
AS (
SELECT t.id, t.ParentID
FROM @temp t
WHERE t.ID = @startNode
UNION ALL
SELECT t.id, t.ParentID
FROM @temp t
JOIN Up c ON t.id = c.ParentID
)
--SELECT * FROM Up
,TheTree (ID,ParentID)
AS (
SELECT ID, ParentID
FROM Up
WHERE ParentID is null
UNION ALL
SELECT t.id, t.ParentID
FROM @temp t
JOIN TheTree tr ON t.ParentID = tr.ID
)
SELECT * FROM TheTree
谢谢
答案 0 :(得分:1)
这是一种技术,您可以选择整个层次结构,包含其所有子节点的特定节点,甚至是已过滤的列表以及它们如何滚动。
注意:请参阅DECLAREs旁边的评论
Declare @YourTable table (id int,pt int,name varchar(50))
Insert into @YourTable values
(1,null,'1'),(2,1,'2'),(3,1,'3'),(4,2,'4'),(5,2,'5'),(6,3,'6'),(7,null,'7'),(8,7,'8')
Declare @Top int = null --<< Sets top of Hier Try 2
Declare @Nest varchar(25) = '|-----' --<< Optional: Added for readability
Declare @Filter varchar(25) = '' --<< Empty for All or try 4,6
;with cteP as (
Select Seq = cast(1000+Row_Number() over (Order by name) as varchar(500))
,ID
,pt
,Lvl=1
,name
From @YourTable
Where IsNull(@Top,-1) = case when @Top is null then isnull(pt,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',1000+Row_Number() over (Order by r.name)) as varchar(500))
,r.ID
,r.pt
,p.Lvl+1
,r.name
From @YourTable r
Join cteP p on r.pt = p.ID)
,cteR1 as (Select *,R1=Row_Number() over (Order By Seq) From cteP)
,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select Distinct
A.R1
,B.R2
,A.ID
,A.pt
,A.Lvl
,name = Replicate(@Nest,A.Lvl-1) + A.name
From cteR1 A
Join cteR2 B on A.ID=B.ID
Join (Select R1 From cteR1 where IIF(@Filter='',1,0)+CharIndex(concat(',',ID,','),concat(',',@Filter+','))>0) F on F.R1 between A.R1 and B.R2
Order By A.R1
答案 1 :(得分:1)
咩。这避免了使用两个CTE,但结果是一个蛮力的kludge几乎不符合“光滑”的条件,因为如果你的桌子大小合适,它就不会有效。它会:
我在TargetId出现在多个层次结构中的偶然事件中输入了“TreeNumber”列,或者如果您在一次传递中有多个值要检查。添加“深度”以使输出更清晰。
像John John这样的更复杂的解决方案可能会做,而更详细的表格结构可以做更多更微妙的技巧。
DECLARE @startNode INT = 4
;WITH cteAllTrees (TreeNumber, Depth, ID, ParentID, ContainsTarget)
AS (
SELECT
row_number() over (order by ID) TreeNumber
,1
,ID
,ParentID
,case
when ID = @startNode then 1
else 0
end ContainsTarget
FROM @temp
WHERE ParentId is null
UNION ALL
SELECT
tr.TreeNumber
,tr.Depth + 1
,t.id
,t.ParentID
,case
when tr.ContainsTarget = 1 then 1
when t.ID = @startNode then 1
else 0
end ContainsTarget
FROM @temp t
INNER JOIN cteAllTrees tr
ON t.ParentID = tr.ID
)
SELECT
TreeNumber
,Depth
,ID
,ParentId
from cteAllTrees
where TreeNumber in (select TreeNumber from cteAllTrees where ContainsTarget = 1)
order by
TreeNumber
,Depth
,ID