我的SQL Server数据库中有以下数据:
Id | Name | LinkedId
---+------+----------
1 | A | 1
2 | B | 2
3 | C | 1
4 | D | 3
5 | E | 4
现在我想编写一个存储过程,其中应显示以下记录:
注意:LinkedId
具有与该名称相关联的ID。
例如:“C”与“A”
相关联Id | Name | LinkedId
---+------+---------
1 | A | 1
2 | B | 2
3 | C | 1
4 | D | 1 //here instead of showing 3, it showed 1 which is the bottom most value in the tree
5 | E | 1 //same case as the above
问题:
对于这种情况,根据我的有限知识,我只能想到使用JOINS(LEFT,INNER),但在这种情况下,这还不足以获得它的最底层链接ID。
编辑(输出):
我希望所有项目(直接和间接)与项目“C”
相关联Id | Name |
---+------+
3 | C |
4 | D |
5 | E |
答案 0 :(得分:2)
您可以使用递归函数
一个简单的解释,使用CTE的递归函数是common table expression
,它在计算时使用它自己。它包括:
- 调用例程。
醇>第一次调用递归CTE 由UNION ALL连接的一个或多个CTE_query_definition组成, UNION,EXCEPT或INTERSECT运算符。
因为这些查询定义 形成CTE结构的基本结果集,它们被称为 主播成员。
CTE_query_definitions被视为锚成员 除非他们参考CTE本身。
所有锚点成员查询 定义必须位于第一个递归成员之前 定义,并且必须使用UNION ALL运算符来连接最后一个 具有第一个递归成员的锚成员。
- 递归调用例程。
醇>递归调用包括一个或多个 CTE_query_definitions由引用该引用的UNION ALL运算符连接 CTE本身。这些查询定义称为递归 成员。
- 终止检查。
醇>终止检查是隐含的; 如果没有从前一个返回任何行,则递归停止 调用
参考链接:Recursive query using CTE
Simple Example of Recursive CTE Cte sql server
DECLARE @SampleData AS TABLE (Id int, Name varchar(10), LinkedId int)
INSERT INTO @SampleData
VALUES (1, 'A', 1), (2, 'B', 2),
(3, 'C', 1),(4, 'D', 3),(5, 'A', 4)
;WITH temp AS
(
SELECT sd.Id, sd.Name, sd.Id AS RootId
FROM @SampleData sd WHERE sd.LinkedId = sd.Id -- Invocation of the routine, in this case it's root node of tree.
UNION ALL
-- Recursive invocation of the routine
SELECT sd.Id, sd.Name, t.RootId AS RootId
FROM temp t
INNER JOIN @SampleData sd ON sd.LinkedId = t.Id AND sd.LinkedId <> sd.Id
-- Termination check: sd.LinkedId = t.Id AND sd.LinkedId <> sd.Id.
-- It make recursive query is not an infinitive loop
)
SELECT t.Id, t.Name, t.RootId AS LinkedId
FROM temp t
OPTION (MAXRECURSION 0) -- this option remove recursive max depth, default is 100.
对于新输出,您可以更改The first invocation of the
recursive CTE
;WITH temp AS
(
SELECT sd.Id, sd.Name, sd.Id AS RootId
FROM @SampleData sd WHERE sd.Id = 3
UNION ALL
-- Recursive invocation of the routine
SELECT sd.Id, sd.Name, t.RootId AS RootId
FROM temp t
INNER JOIN @SampleData sd ON sd.LinkedId = t.Id AND sd.LinkedId <> sd.Id
-- Termination check: sd.LinkedId = t.Id AND sd.LinkedId <> sd.Id.
-- It make recursive query is not an infinitive loop
)
SELECT t.Id, t.Name, t.RootId AS LinkedId
FROM temp t
OPTION (MAXRECURSION 0) -- this option remove recursive max depth, default is 100.
答案 1 :(得分:0)
您想要一个递归过程:
with cte as (
select t.id, t.name, t.linkedid, 1 as lev
from t
where t.linkedid = t.id
union all
select t.id, t.name, cte.linkedid, cte.lev + 1
from t join
cte
on cte.id = t.linkedid and t.linkedid <> t.id
)
select id, name, linkedid
from cte;
Here是否在实践中发挥作用。