SQL Server 2008 - 获取最底层链接的记录

时间:2017-04-14 10:49:04

标签: sql sql-server sql-server-2008 stored-procedures logic

我的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    | 

2 个答案:

答案 0 :(得分:2)

您可以使用递归函数

一个简单的解释,使用CTE的递归函数是common table expression,它在计算时使用它自己。它包括:

  
      
  1. 调用例程。
  2.         

    第一次调用递归CTE   由UNION ALL连接的一个或多个CTE_query_definition组成,   UNION,EXCEPT或INTERSECT运算符。

         

    因为这些查询定义   形成CTE结构的基本结果集,它们被称为   主播成员。

         

    CTE_query_definitions被视为锚成员   除非他们参考CTE本身。

         

    所有锚点成员查询   定义必须位于第一个递归成员之前   定义,并且必须使用UNION ALL运算符来连接最后一个   具有第一个递归成员的锚成员。

         
        
    1. 递归调用例程。
    2.         

      递归调用包括一个或多个   CTE_query_definitions由引用该引用的UNION ALL运算符连接   CTE本身。这些查询定义称为递归   成员。

           
          
      1. 终止检查。
      2.         

        终止检查是隐含的;   如果没有从前一个返回任何行,则递归停止   调用

参考链接: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.

演示链接:Rextester

对于新输出,您可以更改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是否在实践中发挥作用。