题目描述

(通过次数9,776 | 提交次数12,069,通过率81.00%)

员工表:Employees
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| employee_id   | int     |
| employee_name | varchar |
| manager_id    | int     |
+---------------+---------+
employee_id 是这个表的主键。
这个表中每一行中,employee_id 表示职工的 ID,employee_name 表示职工的名字,manager_id 表示该职工汇报工作的直线经理。
这个公司 CEO 是 employee_id = 1 的人。

用 SQL 查询出所有直接或间接向公司 CEO 汇报工作的职工的 employee_id 。
由于公司规模较小,经理之间的间接关系不超过 3 个经理。
可以以任何顺序返回无重复项的结果。

查询结果示例如下:
Employees table:
+-------------+---------------+------------+
| employee_id | employee_name | manager_id |
+-------------+---------------+------------+
| 1           | Boss          | 1          |
| 3           | Alice         | 3          |
| 2           | Bob           | 1          |
| 4           | Daniel        | 2          |
| 7           | Luis          | 4          |
| 8           | Jhon          | 3          |
| 9           | Angela        | 8          |
| 77          | Robert        | 1          |
+-------------+---------------+------------+

Result table:
+-------------+
| employee_id |
+-------------+
| 2           |
| 77          |
| 4           |
| 7           |
+-------------+

公司 CEO 的 employee_id 是 1.
employee_id 是 2 和 77 的职员直接汇报给公司 CEO。
employee_id 是 4 的职员间接汇报给公司 CEO 4 --> 2 --> 1 。
employee_id 是 7 的职员间接汇报给公司 CEO 7 --> 4 --> 2 --> 1 。
employee_id 是 3, 8 ,9 的职员不会直接或间接的汇报给公司 CEO。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/all-people-report-to-the-given-manager
//测试数据
Create table If Not Exists Employees (employee_id int, employee_name varchar(30), manager_id int);

insert into Employees (employee_id, employee_name, manager_id) values ('1', 'Boss', '1');
insert into Employees (employee_id, employee_name, manager_id) values ('3', 'Alice', '3');
insert into Employees (employee_id, employee_name, manager_id) values ('2', 'Bob', '1');
insert into Employees (employee_id, employee_name, manager_id) values ('4', 'Daniel', '2');
insert into Employees (employee_id, employee_name, manager_id) values ('7', 'Luis', '4');
insert into Employees (employee_id, employee_name, manager_id) values ('8', 'John', '3');
insert into Employees (employee_id, employee_name, manager_id) values ('9', 'Angela', '8');
insert into Employees (employee_id, employee_name, manager_id) values ('77', 'Robert', '1');

解题思路

题目要求从CEO(employee_id = 1)出发,找出直接下属,以及下属的下属,下属的下属的下属。

因为题目中已经说明公司层级不高,最高3级。那么可以通过穷举的方式来实现。

也就是说,**第一步**:找到CEO的直接下属;

**第二步**:找到下属的下属;

**第三步**:找到下属的下属的下属;

说起来比较拗口,但思路就是这样。如果层级更深,就继续向下查。

最后一步:合并上面3步找到的所有人,然后去重即可。

上面这种方法,SQL写起来比较简单。但仅仅针对层级不深的情况比较适用。

如果层级比较深,这种方法就显得非常臃肿。

显然,递归是一个比较好的方法。

在推文单挑力扣(LeetCode)SQL题:1613. 找到遗失的ID(难度:中等)中,我介绍了几种不同数据库实现递归的方法。

今天主要介绍下Oracle数据库中使用connect by实现递归的方法。

Oracle中,使用connect by实现递归的语法如下:

select * 
from table 
[start with condition]
connect by [nocycle] [prior] id=parentid

其中,start with condition是用来限制取出第一层数据的条件;

id = parentid是用来从第一层数据出发,查出下一层次的数据的条件。

当prior的位置不变,后面条件为id = parentid时,表示从根节点出发,查出以下所有层级的节点;

当prior的位置不变,后面条件为parentid = id时,表示从叶子节点出发,查出以上所有层级的节点;

当然,也可以条件不变,改变prior关键字的位置,可以实现同样的效果。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
select a.employee_id
from employees a
where a.employee_id <> 1
start with a.manager_id  = 1
connect by nocycle prior a.employee_id = a.manager_id 
group by a.employee_id;
picture loss