确定子父表中所有叶节点从根开始的第一个子节点

问题描述 投票:0回答:1

我有这张桌子

emp_no  unq_key          emp_id          mgr_id
7518870 2244087948  2244087965  2244087948
7518870 2244087948  2333920909  2244087948
7518870 2244087948  2244087950  2244087948
7518870 2244087948  2244087948  2340921616
7518870 2244087948  2244087963  2244087948
7518870 2244087948  2244087962  2244087961
7518870 2244087948  2244088015  2244087951
7518870 2244087948  2358036768  2244087955
7518870 2244087948  2244087952  2244087951
7518870 2244087948  2244087953  2244087952
7518870 2244087948  2244460352  2244087965
7518870 2244087948  2244087957  2244087948
7518870 2244087948  2277248665  2277248664
7518870 2244087948  2277248667  2244087965
7518870 2244087948  2340921670  2244087955
7518870 2244087948  2244087959  2244087948
7518870 2244087948  2244087960  2244087948
7518870 2244087948  2352651692  2244087951
7518870 2244087948  2314063120  2244087955
7518870 2244087948  2244088014  2244087952
7518870 2244087948  2244087954  2244087951
7518870 2244087948  2244087956  2244087955
7518870 2244087948  2244087955  2244087951
7518870 2244087948  2277248664  2244087951
7518870 2244087948  2280898236  2277248645
7518870 2244087948  2277248645  2244087951
7518870 2244087948  2358036769  2244087948
7518870 2244087948  2244087958  2244087948
7518870 2244087948  2244088016  2244088015
7518870 2244087948  2244087951  2244087948

我的根记录是unq_key=emp_id。我正在尝试打印所有叶节点的第一个相应的 emp_id 子节点。我正在尝试识别下面的代码,但没有得到正确的第一个孩子。

例如:2244088016是第一个子节点的叶节点:2244087951

如有任何帮助,我们将不胜感激。预先感谢。


;WITH   tree_view AS (
    SELECT 
         emp_no
         ,unq_key
         ,emp_id
         ,mgr_id
         ,0 AS order_sequence
         ,0 AS generation_number
          
    FROM 
        #temp_employees
    WHERE 
        unq_key=emp_id 
    UNION ALL 
        SELECT 
            parent.emp_no,
             parent.unq_key,
             parent.emp_id,
             parent.mgr_id 
             ,order_sequence +1 AS order_sequence
             ,generation_number + 1 AS generation_number
        FROM 
            #temp_employees parent
            JOIN tree_view tv
          ON parent.mgr_id = tv.emp_id
    ) 
    SELECT
       RIGHT('------------',generation_number*3) + ' Emp :'+ cast( emp_id as varchar(100))
      ,*
    FROM 
        tree_view   
    ORDER BY order_sequence; 

只需要一个包含第一个孩子的附加列。

sql-server t-sql common-table-expression
1个回答
0
投票

我将“第一个子节点”解释为“给定从根到每个叶子的路径,找到根之后的第一个节点”。换句话说,对于根节点来说,没有第一个子节点,而对于根节点的所有直接子节点来说,第一个子节点就是它自己。

如果这是正确的,这里有一个使用闭包表的解决方案。闭包表包含从每个节点到其谱系中每个其他节点的边(不仅到其父节点,还包括其父节点的父节点,等等,一直到根),深度是节点之间的距离。

请注意,为了做到这一点,递归 CTE 从叶级别而不是根级别开始。

with emps as
(
   select   *
   from
            (
               values
                  (7518870, 2244087948, 2244087965, 2244087948),
                  (7518870, 2244087948, 2333920909, 2244087948),
                  (7518870, 2244087948, 2244087950, 2244087948),
                  (7518870, 2244087948, 2244087948, 2340921616),
                  (7518870, 2244087948, 2244087963, 2244087948),
                  (7518870, 2244087948, 2244087962, 2244087961),
                  (7518870, 2244087948, 2244088015, 2244087951),
                  (7518870, 2244087948, 2358036768, 2244087955),
                  (7518870, 2244087948, 2244087952, 2244087951),
                  (7518870, 2244087948, 2244087953, 2244087952),
                  (7518870, 2244087948, 2244460352, 2244087965),
                  (7518870, 2244087948, 2244087957, 2244087948),
                  (7518870, 2244087948, 2277248665, 2277248664),
                  (7518870, 2244087948, 2277248667, 2244087965),
                  (7518870, 2244087948, 2340921670, 2244087955),
                  (7518870, 2244087948, 2244087959, 2244087948),
                  (7518870, 2244087948, 2244087960, 2244087948),
                  (7518870, 2244087948, 2352651692, 2244087951),
                  (7518870, 2244087948, 2314063120, 2244087955),
                  (7518870, 2244087948, 2244088014, 2244087952),
                  (7518870, 2244087948, 2244087954, 2244087951),
                  (7518870, 2244087948, 2244087956, 2244087955),
                  (7518870, 2244087948, 2244087955, 2244087951),
                  (7518870, 2244087948, 2277248664, 2244087951),
                  (7518870, 2244087948, 2280898236, 2277248645),
                  (7518870, 2244087948, 2277248645, 2244087951),
                  (7518870, 2244087948, 2358036769, 2244087948),
                  (7518870, 2244087948, 2244087958, 2244087948),
                  (7518870, 2244087948, 2244088016, 2244088015),
                  (7518870, 2244087948, 2244087951, 2244087948)
            ) t (emp_no, unq_key, emp_id, mgr_id)
),
closure as
(
      select   emp_id      = emp_id,
               mgr_id      = emp_id,             
               emp_no,
               unq_key,
               distance = 0
      from     emps
      union all
      select   e.emp_id,
               c.mgr_id,            
               e.emp_no,
               e.unq_key,
               c.distance + 1
      from     emps     e
      join     closure  c on c.emp_id = e.mgr_id
)

select      tree = concat(replicate('-', tree.distance * 3), ' Emp :', tree.emp_id),
            tree.emp_no,
            tree.unq_key,
            tree.emp_id,
            tree.mgr_id,
            tree.distance,
            first_child = tier0.mgr_id
from        (select * from closure where mgr_id = unq_key) tree
outer apply (select mgr_id from closure where emp_id = tree.emp_id and distance = tree.distance - 1) tier0
order by    tree.distance;

tree
子查询用于仅获取闭包表中表示从每个叶子到根的边的行。从根开始的这些行的
distance
提供了所需的缩进级别。

tier0
子查询然后找到距离比到根的距离小一的叶子的边缘。

© www.soinside.com 2019 - 2024. All rights reserved.