【问题标题】:Recursive SQL self join递归 SQL 自连接
【发布时间】:2017-05-28 18:18:28
【问题描述】:

我有以下员工表,EmpIDManagerID 之间存在外键关系。

员工表

期望的输出

我希望能够以由> 分隔的分层顺序显示员工姓名,从最高管理者到底层,其中 EmpID 是层次结构底部员工的 ID。

我知道我可以通过使用以下 SQL 将表连接到自身来获得所需的输出。

select e1.empID, e1.DeptID, e2.Name + ' > ' + e1.Name as Description
from employee e1
left join employee e2
on e1.managerId = e2.empId

我也知道我可以在上述查询中添加更多左连接以获得所需的输出。但是层次结构的深度没有限制,所以我想它需要动态完成。

任何帮助将不胜感激

【问题讨论】:

标签: sql tsql join sql-server-2012 self-join


【解决方案1】:

你想要一个递归 CTE:

with e as (
      select cast(name as varchar(max)) as list, empId, 0 as level
      from employees
      where managerID is null
      union all
      select e.list + '>' + e2.name, e2.empId, level + 1
      from e join
           employees e2
           on e.empId = e2.managerId
     )
select e.*
from e
where not exists (select 1
                  from employees e2
                  where e2.managerId = e.empId
                 );

【讨论】:

  • 使用 CTE 时,您必须使用 MAXRecusrion 设置为 0,因为当您不指定 maxrecusrion 时,默认大小为 100。上限为 32767 sql-server-helper.com/error-messages/msg-310.aspx
  • @RahulNeekhra 。 . .那是真实的。但是,如果层次结构下降 10 级,更不用说 100 级,我会感到惊讶。
  • 感谢您的评论。然后你就可以管理了。此评论对未来的其他用户有帮助
【解决方案2】:
declare @Employees table (
    EmpId      int          ,
    DeptId     int          ,
    Name       varchar(30)  ,
    ManagerId  int
);

insert into @Employees values
( 1, 1, 'Zippy'    , 2    ),
( 2, 1, 'George'   , 3    ),
( 3, 1, 'Bungle'   , 4    ),
( 4, 1, 'Geoffrey' , null ),
( 5, 2, 'Rod'      , 6    ),
( 6, 2, 'Jane'     , 7    ),
( 7, 2, 'Freddy'   , null );

with cte as
(
    select   
        EmpId      ,
        DeptId     ,
        ManagerId  ,
        Path       =  cast('' as varchar(4000)),
        Name       ,                
        Level      =  0        
    from
        @Employees    
    where
        ManagerId is null

    union all 

    select 
        EmpId     =  e.EmpId,
        DeptId    =  e.DeptId,
        ParentId  =  e.ManagerId,
        Path      =  cast(concat(cte.Path, cte.Name, ' › ') as varchar(4000)),
        Name      =  e.Name,        
        Level     =  cte.Level + 1    
    from 
        @Employees e
        inner join cte on cte.EmpId = e.ManagerId
)
select 
    EmpId      ,
    DeptId     ,
    ManagerId  ,    
    Path       ,
    Name       ,
    FullPath   =  Path + Name,    
    Level        
from 
    cte
order by
    FullPath;

【讨论】:

    猜你喜欢
    • 2013-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-06
    • 2017-08-14
    相关资源
    最近更新 更多