Select 递归查询

Select Query with Recursion

我有两个 table 包含员工姓名 (TableB) 和员工层次结构 (TableA)(来自 TableA 的 manager_id 可以是 employee_id 在同一个 table 中) .

TableA
UniqueId    Employee_ID Manager_ID
1            101         102
2            102         103
3            103         104
4            105         106
5            106         null


TableB
Employee_ID  Employee_Name
101          First
102          Second
103          Third
104          Fourth
105          Fifth
106          Sixth

我需要如下输出:

Employee_ID Employee_Name   Transferred
101         First           True
102         Second          True
103         Third           True
105         Fifth           False
106         Sixth           False

每个员工的 调动 列计算为 =

isTransferred(Employee_ID)
{
    If(Manager_ID  is null) return false;
    If(Manager_ID is present as employee_id in table A)
    {
       return isTransferred(manager_ID)
    }
    else
    {
       return true;
    }
}

有没有办法在一个 select 语句中得到结果?

您可以使用递归 CTE,然后为每个员工获取 "recursion" 的最后一个级别。一旦你有了它,你只需检查最后一层的 manager_id 看看它是否被转移。

例如:

with
tablea as (
  select 1 as uniqueId, 101 as employee_id, 102 as manager_id from dual union all
  select 2  as uniqueId, 102 as employee_id, 103 as manager_id from dual union all
  select 3  as uniqueId, 103 as employee_id, 104 as manager_id from dual union all
  select 4  as uniqueId, 105 as employee_id, 106 as manager_id from dual union all
  select 5  as uniqueId ,106 as employee_id, null from dual 
),
tableb as (
  select 101 as employee_id, 'first' as employee_name from dual union all
  select 102 as employee_id, 'second' as employee_name from dual union all
  select 103 as employee_id, 'third' as employee_name from dual union all
  select 104 as employee_id, 'fourth' as employee_name from dual union all
  select 105 as employee_id, 'fifth' as employee_name from dual union all
  select 106 as employee_id, 'sixth' as employee_name from dual 
),
n (employee_id, employee_name, lvl, manager_id) as (
  select b.employee_id, b.employee_name, 1, a.manager_id
  from tablea a
  join tableb b on a.employee_id = b.employee_id
union all
  select
    n.employee_id, n.employee_name, lvl + 1, a.manager_id
  from n
  join tablea a on a.employee_id = n.manager_id
),
m (employee_id, max_lvl) as (
  select employee_id, max(lvl) from n group by employee_id
)
select n.employee_id, n.employee_name, 
  case when n.manager_id is not null then 'True' else 'False' end as transferred
from n
join m on n.employee_id = m.employee_id and n.lvl = m.max_lvl
order by n.employee_id

结果:

EMPLOYEE_ID  EMPLOYEE_NAME  TRANSFERRED
-----------  -------------  -----------
        101  first          True       
        102  second         True       
        103  third          True       
        105  fifth          False      
        106  sixth          False      

您可以按如下方式通过一次遍历树来完成此操作:

  • 外部加入员工的管理链
  • 通过将 unique_id 映射到 "impossible" 值来查找没有经理的员工,例如-1
  • 使用此连接的结果沿着树向下走,从管理器为空的行开始
  • 为根行获取步骤 2 中表达式的值;如果这是 "impossible" 值,则转移 => true
  • 过滤掉不可能值的行

这给出了类似的东西:

with table_a ( UniqueId, Employee_ID, Manager_ID ) as (
  select 1, 101, 102 from dual union all 
  select 2, 102, 103 from dual union all 
  select 3, 103, 104 from dual union all
  select 4, 105, 106 from dual union all 
  select 5, 106, null from dual 
), Table_b ( Employee_ID, Employee_Name ) as (
  select 101, 'First' from dual union all
  select 102, 'Second' from dual union all
  select 103, 'Third' from dual union all
  select 104, 'Fourth' from dual union all
  select 105, 'Fifth' from dual union all
  select 106, 'Sixth' from dual
), rws as (
  select b.*, a.Manager_ID,
         nvl ( a.UniqueId, -1 ) transfer
  from   table_b b
  left join table_a a
  on   b.Employee_ID = a.Employee_ID
)
  select r.*, 
         case connect_by_root transfer
           when -1 then 'true'
           else 'false'
         end transferred
  from   rws r
  where  transfer > 0
  start  with manager_id is null
  connect by manager_id = prior employee_id;

EMPLOYEE_ID    EMPLOYEE_NAME    MANAGER_ID    TRANSFER    TRANSFERRED   
           103 Third                      104           3 true           
           102 Second                     103           2 true           
           101 First                      102           1 true           
           106 Sixth                   <null>           5 false          
           105 Fifth                      106           4 false