【问题标题】:Full recursive employee-boss relation in SQL ServerSQL Server 中的完全递归员工-老板关系
【发布时间】:2023-11-20 22:01:01
【问题描述】:

我需要获取直接或间接依赖于某个人的所有员工的姓名。使用本例中的查询(来自https://rextester.com/WGVRGJ67798),

create table employee(
id int not null,
employee varchar(10) not null,
boss int null    
)

insert into employee values
(1,'Anna',null),
(2,'Bob',1),
(3,'Louis',1),
(4,'Sara',2),
(5,'Sophie',2),
(6,'John',4);

with boss as (
     select id, employee, boss, cast(null as varchar(10)) as name
     from employee 
     where boss is null
    
     union all 
    
     select e.id, e.employee, b.id, b.employee
     from employee e 
     join boss b on b.id = e.boss
 )

select * from boss

我可以得到这个结果:

但是,我需要看到这个:

这就像显示一个人与他或她“下方”的所有员工之间所有可能的关系。

【问题讨论】:

  • 如果你用谷歌搜索T-SQL hierarchical query,你会发现你需要一个递归 CTE
  • @Larnu 好的,我的问题是如何修改递归 CTE 查询以获得第二张图像的绿色部分。通过 cte 查询,我得到了第一个查询的结果。这是我的疑问。
  • 我已将您链接中的代码添加到您上面发布的问题中。请注意,重要的是问题要独立完成,而不依赖于其他网站(除非某些内容太大而无法包含在此处)。这是因为如果外部站点将来消失,那么您的问题对于以后可能得到答案的读者来说将不再有意义。因此,可以参考其他网站,但将它们用作补充/有用的来源,而不是必要的信息。
  • @RBarryYoung 非常感谢您的建议。下次我会记住的。

标签: sql sql-server hierarchical-data recursive-query


【解决方案1】:

您可以颠倒逻辑:您可以从叶子开始,向根部走,而不是从老板(根)开始走向员工(叶子)。这使您可以随时生成中间关系:

with cte as (
     select e.id, e.employee, e.boss, b.employee name, b.boss new_boss
     from employee e
     left  join employee b on b.id = e.boss
     union all 
     select c.id, c.employee, c.new_boss, e.employee, e.boss
     from cte c 
     join employee e on e.id = c.new_boss
)
select id, employee, boss, name 
from cte
order by id, boss

Demo on DB Fiddle

编号 |员工 |老板 |姓名 -: | :------- | ---: | :--- 1 |安娜 | | 2 |鲍勃 | 1 |安娜 3 |路易斯 | 1 |安娜 4 |萨拉 | 1 |安娜 4 |萨拉 | 2 |鲍勃 5 |苏菲 | 1 |安娜 5 |苏菲 | 2 |鲍勃 6 |约翰 | 1 |安娜 6 |约翰 | 2 |鲍勃 6 |约翰 | 4 |萨拉

【讨论】:

  • 感谢您提供如此清晰直观的解释。除非我遗漏了什么,否则这应该是选择的解决方案
【解决方案2】:

我喜欢这种东西的hierarchyid。

use tempdb;
drop table if exists employee;
drop table if exists #e;

create table employee(
    id int not null,
    employee varchar(10) not null,
    boss int null    
)

insert into employee values
(1,'Anna',null),
(2,'Bob',1),
(3,'Louis',1),
(4,'Sara',2),
(5,'Sophie',2),
(6,'John',4);

with boss as (
     select id, employee, boss, 
        cast(concat('/', id, '/') as hierarchyid) as h
     from employee 
     where boss is null
    
     union all 
    
     select e.id, e.employee, b.id, 
        cast(concat(b.h.ToString(), e.id, '/') as hierarchyid)
     from employee e 
     join boss b on b.id = e.boss
 )

select *
into #e
from boss

select e.id, e.employee, b.id, b.employee, b.h.ToString()
from #e as e
left join #e as b
    on e.h.IsDescendantOf(b.h) = 1
    and e.id <> b.id;

我主要按原样使用您的代码并更改了以下内容:

  1. 我没有在递归 CTE 中跟踪老板,而是构建了一个 hierarchyid 路径,该路径一直通向层次结构的根。

  2. 将 cte 的结果推送到临时表中

  3. 从临时表中选择,使用自联接,其中联接条件是“内部表的员工概念在外部表的管理链中的任何位置”。

注意,对于join,我排除了员工向自己报告的情况;在这种情况下,你不能成为自己的老板(即使 IsDescendantOf 方法会建议其他方法!)。

【讨论】:

    【解决方案3】:

    类似的东西。有两个递归。首先,得到第一次递归代表老板-->员工关系的h_level。其次,将第一行的每一行视为新递归中的叶节点,以查找直接和间接的层次关系。

    数据

    drop table if exists Employee;
    go
    create table employee(
      id       int not null,
      employee varchar(10) not null,
      boss     int null)
    
    insert into employee values
    (1,'Anna',null),
    (2,'Bob',1),
    (3,'Louis',1),
    (4,'Sara',2),
    (5,'Sophie',2),
    (6,'John',4);
    

    查询

    ;with 
    boss(id, employee, boss, h_level) as (
         select id, employee, boss, 0
         from employee 
         where boss is null
         union all 
         select e.id, e.employee, b.id, b.h_level+1
         from employee e 
              join boss b on b.id = e.boss),
    downlines(id, employee, boss, h_level, d_level) as (
         select id, employee, boss, h_level, 0
         from boss 
         union all 
         select b.id, b.employee, d.id, d.h_level, d.d_level+1
         from boss b 
              join downlines d on d.id = b.boss)
    select * 
    from downlines
    order by h_level, d_level;
    

    输出

    id  employee    boss    h_level d_level
    1   Anna    NULL0   0
    2   Bob     1   0   1
    3   Louis   1   0   1
    4   Sara    2   0   2
    5   Sophie  2   0   2
    6   John    4   0   3
    2   Bob     1   1   0
    3   Louis   1   1   0
    4   Sara    2   1   1
    5   Sophie  2   1   1
    6   John    4   1   2
    4   Sara    2   2   0
    5   Sophie  2   2   0
    6   John    4   2   1
    6   John    4   3   0
    

    【讨论】:

      最近更新 更多