【发布时间】:2019-05-24 11:25:06
【问题描述】:
【问题讨论】:
-
为什么
E的新节点会是A?A是E的父级,而不是相反。请解释你的逻辑。 -
我想得到每个原始节点的古代父亲。A是E的古代父亲,就像A是C和D的古代父亲一样。
标签: sql sql-server recursion
【问题讨论】:
E的新节点会是A? A 是E 的父级,而不是相反。请解释你的逻辑。
标签: sql sql-server recursion
这是使用递归 CTE 的一种方法:
WITH cte AS (
SELECT t1.ID, t1.Node, t1.Son, t1.Name, CONVERT(VARCHAR(MAX), t1.Node + ',') AS path
FROM yourTable t1
WHERE NOT EXISTS (SELECT 1 FROM yourTable t2 WHERE t1.Node = t2.Son)
UNION ALL
SELECT t1.ID, t1.Node, t1.Son, t1.Name, CONVERT(VARCHAR(MAX), path + ',' + t2.Son)
FROM yourTable t1
INNER JOIN cte t2
ON t1.Node = t2.Son
)
SELECT
ID,
Node AS [Original Node],
CASE WHEN CHARINDEX(',', path) = 0
THEN path
ELSE LEFT(path, CHARINDEX(',', path) - 1) END AS [New Node],
Name
FROM cte
ORDER BY ID;
说明:要了解其工作原理,查看 CTE 上以下直接查询的输出可能会有所帮助:
SELECT *
FROM cte
ORDER BY ID;
希望很清楚这个技巧是如何工作的。我们递归地构建一条路径,从所有原始祖先开始。当递归 CTE 完成时,我们有一个表,其中每个节点都有一条完整的路径,一直到原始祖先。然后,我们只需要取序列中的第一项来找到那个祖先。
【讨论】:
设法回答自己,但不完全是上面提到的标签。
Drop table if exists ##Nodes
CREATE TABLE ##Nodes
(
NodeID varchar(20) NOT NULL,
SonNodeID varchar(20) NULL,
[Name] varchar(20) NULL
)
enter code here
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('A', 'C','First')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('B', NULL,'Second')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('C', 'D','Third')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('D', 'E','Fourth')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('E', NULL,'Fifth')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('F', 'I','Sixth')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('G', NULL,'Seventh')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('H', NULL,'Eighth')
INSERT INTO ##Nodes (NodeID, SonNodeID, [Name]) VALUES ('I', NULL,'Nineth')
WITH Nodes AS
(
--initialization
SELECT NodeID, SonNodeID, [Name], Father = NodeID , 1 AS GenerationsRemoved
FROM ##Nodes
UNION ALL
----recursive execution
SELECT N.NodeID, N.SonNodeID, P.[Name], Father = P.Father, P.GenerationsRemoved + 1
FROM Nodes AS P
INNER JOIN ##Nodes AS N
ON P.SonNodeID = N.NodeID
WHERE P.GenerationsRemoved <= 100
)
SELECT a.NodeID, AncientFather = Father, a.[Name]
FROM Nodes as a
join
(
Select NodeID, MaxGen = max(GenerationsRemoved)
from Nodes
group by NodeID
)as b on a.NodeID = b.NodeID
and a.GenerationsRemoved = b.MaxGen
ORDER BY a.NodeID
结果:
【讨论】:
我知道它并不完美,但这个可以正常工作并提供您想要的结果:
select t1.ID, t1.NODE as ORIGINAL_NODE,
CASE
when t4.SON is not null then t4.NODE
when t3.SON is not null then t3.NODE
when t2.SON is not null then t2.NODE
else t1.NODE
END as NEW_NODE,
CASE
when t4.NAME is not null then t4.NAME
when t3.NAME is not null then t3.NAME
when t2.NAME is not null then t2.NAME
else t1.NAME
END as NAME
from Table t1
left outer join Table t2
on t1.NODE = t2.SON
left outer join Table t3
on t2.NODE = t3.SON
left outer join Table t4
on t3.NODE = t4.SON
order by t1.ID
【讨论】: