SQL递归:获取父项和后代之间的所有可能关系

时间:2017-08-30 18:33:49

标签: sql recursive-query

我想运行一个递归CTE,以便我可以使用表1中提供的信息获得表2.

表1:

Employee  | ReportsTo
a           NULL
b           a
c           b
d           c

表2:

Employee  | ReportsTo  | depth
a           NULL         0
b           a            1
c           a            2
d           a            3
c           b            1
d           b            2
d           c            1

到目前为止,我有:

with cte
    (Employee
    ,ReportsTo
    ,depth)
as
    (
    select  Employee
            ,ReportsTo
            ,0 as depth
    from    [Table 1]
    where   ReportsTo is null

    UNION ALL

    select  a.Employee
            ,a.ReportsTo
            ,b.depth + 1
    from    cte b
    join [Table 1] a    
            on a.ReportsTo = b.Employee
    )

select  *
from    cte
order by depth

返回:

Employee  | ReportsTo | Depth
a           NULL        0
b           a           1
c           b           2
d           c           3

举几个例子来说明我的问题,请注意我错过了员工“d”间接向员工“b”报告的关系。或员工“d”间接向员工“a”报告。

2 个答案:

答案 0 :(得分:0)

试试这个。

with cte
    (root
    ,Employee
    ,ReportsTo
    ,depth)
as
    (
    select  ReportsTo root
            ,Employee
            ,ReportsTo
            ,0 as depth
    from    [Table 1] t1

    UNION ALL

    select  b.root
            ,a.Employee
            ,a.ReportsTo
            ,b.depth + 1
    from    cte b
    join [Table 1] a    
            on a.ReportsTo = b.Employee
    )

select  distinct Employee , root ReportsTo,  depth+1 depth
from    cte
where depth = 0 or root is not null --  needn't null as a boss but on 0 level
order by depth;

答案 1 :(得分:0)

你很亲密。您需要从cte中删除[pid 21477] 14:45:35.713220 read(66, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain; charset=utf-8\r\nServer: Docker/1.10.2 (linux)\r\nX-Content-Type-Options: nosniff\r\nDate: Tue, 05 Sep 2017 21:45:35 GMT\r\nContent-Length: 23\r\nConnection: close\r\n\r\nNo such container: dsm\n", 65536) = 230 [pid 21477] 14:45:35.714067 read(67, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain; charset=utf-8\r\nServer: Docker/1.10.2 (linux)\r\nX-Content-Type-Options: nosniff\r\nDate: Tue, 05 Sep 2017 21:45:35 GMT\r\nContent-Length: 29\r\nConnection: close\r\n\r\nNo such container: db2server\n", 65536) = 236 才能获取分支上的所有节点。 (我还添加了一个concat,因此您可以看到完整的Tree Path以及顶级节点和员工之间的所有节点。)

where ReportsTo is null

现在您拥有了所有节点/分支,您可以选择反映所需深度的节点/分支。 (concat还在最终员工中添加了Tree Path。) 此选择还为顶部节点提供了正确的零深度。

WITH cte
    (TopNode
    ,Employee
    ,ReportsTo
    ,Depth
    ,TreePath)
AS
    (
    SELECT ReportsTo AS TopNode
           ,Employee
           ,ReportsTo
           ,0 AS Depth
           ,CAST(ReportsTo AS VARCHAR(max)) AS TreePath
    FROM   #tblTable1

    UNION ALL

    SELECT cte.TopNode
           ,a.Employee
           ,a.ReportsTo
           ,cte.Depth + 1 AS depth
           ,CAST(cte.TreePath + ' -> ' +
            CAST(a.ReportsTo AS VARCHAR(max)) 
            AS VARCHAR(max)) AS TreePath
    FROM #tblTable1 AS a
    inner join cte
       ON cte.Employee = a.ReportsTo
    )

结果集是:

SELECT
    cte.Employee
    ,cte.TopNode AS ReportsTo
    ,case when cte.ReportsTo is null
             then cte.Depth 
          else cte.Depth + 1
     end AS Depth
    ,case when cte.ReportsTo is null
             then cte.Employee
          else CAST(cte.TreePath + ' -> ' +
               CAST(cte.Employee AS VARCHAR(max)) 
               AS VARCHAR(max)) 
     end AS TreePath
FROM cte
WHERE
   cte.TopNode is not null
   or cte.ReportsTo is null
ORDER BY
   cte.TopNode
   ,cte.Depth;