查询一部分员工时,我正在尝试为其“汇总”到的SVP添加一个字段。
员工与SVP的距离可能为1至5或6度。麻烦的是,我们没有任何特定的层次结构指标可供参考。为此,我必须反复遍历该员工的经理,直到某个经理的经理的标题中标有“ SVP”为止。
如何编写查询来做到这一点?
从相反的方向,我找到了特定SVP的员工(示例中称为BM),说:“员工的经理是BM,或者员工的经理的经理是BM,或者员工的经理的经理是BM”,等等...
对于我的实例,我怀疑我会一次又一次地使用同一sys_user表,每次都跟随manager字段,直到到达标题中带有SVP的用户为止。
+--------+-------------------+-----------+--------+
| sys_id | name | title | manager|
+--------+-------------------+-----------+--------+
| 555789 | Tina Belcher | Contractor| 123456 |
| 123456 | Bob Belcher | Manager | 654321 |
| 654321 | Calvin Fischoeder | SVP | 997755 |
+--------+-------------------+-----------+--------+
SELECT su.Name
, su.Title
, dp.name
, mg.name
FROM sys_user su
LEFT JOIN cmn_department dp
ON dp.sys_id = su.department
LEFT JOIN sys_user mg
ON mg.sys_id = su.manager
WHERE su.Title like ('%contractor%')
我感谢可以提供的任何帮助或提示。感谢您的光临,祝您度过愉快的一天。
答案 0 :(得分:1)
您正在寻找递归CTE:
with cte as (
select su.sys_id, su.name, su.title, su.manager, 1 as lev, 0 as hit_svp
from sys_user su
where su.Title like '%contractor%'
union all
select su.sys_id, su.name, su.title, su.manager, lev + 1,
(case when su.title like '%SVP%' then 1 else 0 end) as hit_svp
from sys_user su join
cte
on cte.manager = su.sys_id
where cte.hit_svp = 0
)
select . . . -- whatever columns you want
from cte; -- you may want additional joins here for other columns
答案 1 :(得分:1)
您的Sys_User
表是一个邻接表,仅提供有关员工及其直接向谁报告的信息。邻接表是编码分层数据的一种方法。它们很不错,因为它们相对较快且紧凑,但是并不是编码分层关系的唯一方法。
要回答您提出的问题,您将受益于将数据重新编码到Closure表中,该表将每个员工映射到其所有直接和间接经理/报告人以及他们的离职程度,以及任何其他相关信息。但是,由于它表示多对多关系,因此您不希望为其加载太多额外的数据。幸运的是,由于使用了递归查询,您可以在运行中轻松创建一个。
要创建关闭表,请先使用0级关系填充该表,其中每个员工均被视为自己的经理/报告人。这样做的理由有点超出我的范围,但这与传递闭包的概念背后的数学有关(因此称为闭包表)。之后,您可以迭代(递归)添加每个其他报告程度。您可以从上至下或从下至上
这是自顶向下版本:
with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
select sys_id
, sys_id
, 0
, case when title like '%SVP%' then 1 else 0 end
, case when title like '%SVP%' then 1 else 0 end
from sys_user
union all
select cur.manager_id
, nxt.sys_id
, cur.degree+1
, cur.is_managing_SVP
, case when nxt.title like '%SVP%' then 1 else 0 end
from closure cur
join sys_user nxt
on nxt.manager = cur.report_id
and nxt.sys_id <> nxt.manager
)
select * from closure
这是自底向上版本:
with closure(manager_id, report_id, degree, is_managing_SVP, is_reporting_svp) as (
select sys_id
, sys_id
, 0
, case when title like '%SVP%' then 1 else 0 end
, case when title like '%SVP%' then 1 else 0 end
from sys_user
union all
select nxt.manager
, cur.report_id
, cur.degree+1
, case when mgr.title like '%SVP%' then 1 else 0 end
, cur.is_reporting_SVP
from closure cur
join sys_user nxt
on nxt.sys_id = cur.manager_id
and nxt.sys_id <> nxt.manager
join sys_user mgr
on mgr.sys_id = nxt.manager
)
select * from closure
如果要生成整个闭合表,使用哪个版本并不重要,但是,如果要优化查询并仅生成部分闭合表,则取决于是否要遍历在树上或下。
生成后,您可以使用封闭表来回答有关SVP的问题,例如每个承包商的SVP是谁:
select r.sys_id, r.name, r.title, c.degree
, c.manager_id SVP_ID
, m.name SVP_name
, m.title SVP_title
from sys_user r
join closure c
on c.report_id = r.sys_id
join sys_user m
on m.sys_id = c.manager_id
where r.title like '%contractor%'
and c.is_managing_svp = 1
sys_id | name | title | degree | SVP_ID | SVP_name | SVP_title -----: | :----------- | :--------- | -----: | -----: | :---------------- | :-------- 555789 | Tina Belcher | Contractor | 2 | 654321 | Calvin Fischoeder | SVP
或者向SVP提交的每份直接和间接报告都叫Calvin Fischoeder:
select m.sys_id manager_id
, m.name
, m.title
, c.degree
, r.sys_id report_id
, r.name report_name
, r.title report_title
from sys_user m
join closure c
on c.manager_id = m.sys_id
join sys_user r
on r.sys_id = c.report_id
where m.name = 'Calvin Fischoeder'
order by degree, report_name
manager_id | name | title | degree | report_id | report_name | report_title ---------: | :---------------- | :---- | -----: | --------: | :---------------- | :----------- 654321 | Calvin Fischoeder | SVP | 0 | 654321 | Calvin Fischoeder | SVP 654321 | Calvin Fischoeder | SVP | 1 | 123456 | Bob Belcher | Manager 654321 | Calvin Fischoeder | SVP | 2 | 555789 | Tina Belcher | Contractor
要查看所有正在使用的查询,请查看此 db<>fiddle