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
我有两个 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