LeetCode_sql刷题(3482.分析组织层级)

news2025/5/16 0:37:03
题目描述:3482. 分析组织层级 - 力扣(LeetCode)

表:Employees

+----------------+---------+
| Column Name    | Type    | 
+----------------+---------+
| employee_id    | int     |
| employee_name  | varchar |
| manager_id     | int     |
| salary         | int     |
| department     | varchar |
+----------------+----------+
employee_id 是这张表的唯一主键。
每一行包含关于一名员工的信息,包括他们的 ID,姓名,他们经理的 ID,薪水和部门。
顶级经理(CEO)的 manager_id 是空的。

编写一个解决方案来分析组织层级并回答下列问题:

  1. 层级:对于每名员工,确定他们在组织中的层级(CEO 层级为 1,CEO 的直接下属员工层级为 2,以此类推)。
  2. 团队大小:对于每个是经理的员工,计算他们手下的(直接或间接下属)总员工数。
  3. 薪资预算:对于每个经理,计算他们控制的总薪资预算(所有手下员工的工资总和,包括间接下属,加上自己的工资)。

返回结果表以 层级 升序 排序,然后以预算 降序 排序,最后以 employee_name 升序 排序。

结果格式如下所示。

示例:

输入:

Employees 表:

+-------------+---------------+------------+--------+-------------+
| employee_id | employee_name | manager_id | salary | department  |
+-------------+---------------+------------+--------+-------------+
| 1           | Alice         | null       | 12000  | Executive   |
| 2           | Bob           | 1          | 10000  | Sales       |
| 3           | Charlie       | 1          | 10000  | Engineering |
| 4           | David         | 2          | 7500   | Sales       |
| 5           | Eva           | 2          | 7500   | Sales       |
| 6           | Frank         | 3          | 9000   | Engineering |
| 7           | Grace         | 3          | 8500   | Engineering |
| 8           | Hank          | 4          | 6000   | Sales       |
| 9           | Ivy           | 6          | 7000   | Engineering |
| 10          | Judy          | 6          | 7000   | Engineering |
+-------------+---------------+------------+--------+-------------+

输出:

+-------------+---------------+-------+-----------+--------+
| employee_id | employee_name | level | team_size | budget |
+-------------+---------------+-------+-----------+--------+
| 1           | Alice         | 1     | 9         | 84500  |
| 3           | Charlie       | 2     | 4         | 41500  |
| 2           | Bob           | 2     | 3         | 31000  |
| 6           | Frank         | 3     | 2         | 23000  |
| 4           | David         | 3     | 1         | 13500  |
| 7           | Grace         | 3     | 0         | 8500   |
| 5           | Eva           | 3     | 0         | 7500   |
| 9           | Ivy           | 4     | 0         | 7000   |
| 10          | Judy          | 4     | 0         | 7000   |
| 8           | Hank          | 4     | 0         | 6000   |
+-------------+---------------+-------+-----------+--------+

解释:

  • 组织结构:
    • Alice(ID:1)是 CEO(层级 1)没有经理。
    • Bob(ID:2)和 Charlie(ID:3)是 Alice 的直接下属(层级 2)
    • David(ID:4),Eva(ID:5)从属于 Bob,而 Frank(ID:6)和 Grace(ID:7)从属于 Charlie(层级 3)
    • Hank(ID:8)从属于 David,而 Ivy(ID:9)和 Judy(ID:10)从属于 Frank(层级 4)
  • 层级计算:
    • CEO(Alice)层级为 1
    • 每个后续的管理层级都会使层级数加 1
  • 团队大小计算:
    • Alice 手下有 9 个员工(除她以外的整个公司)
    • Bob 手下有 3 个员工(David,Eva 和 Hank)
    • Charlie 手下有 4 个员工(Frank,Grace,Ivy 和 Judy)
    • David 手下有 1 个员工(Hank)
    • Frank 手下有 2 个员工(Ivy 和 Judy)
    • Eva,Grace,Hank,Ivy 和 Judy 没有直接下属(team_size = 0)
  • 预算计算:
    • Alice 的预算:她的工资(12000)+ 所有员工的工资(72500)= 84500
    • Charlie 的预算:他的工资(10000)+ Frank 的预算(23000)+ Grace 的工资(8500)= 41500
    • Bob 的预算:他的工资 (10000) + David 的预算(13500)+ Eva 的工资(7500)= 31000
    • Frank 的预算:他的工资 (9000) + Ivy 的工资(7000)+ Judy 的工资(7000)= 23000
    • David 的预算:他的工资 (7500) + Hank 的工资(6000)= 13500
    • 没有直接下属的员工的预算等于他们自己的工资。

注意:

  • 结果先以层级升序排序
  • 在同一层级内,员工按预算降序排序,然后按姓名升序排序
数据准备
CREATE TABLE if not exists Employees (
    employee_id INT,
    employee_name VARCHAR(100),
    manager_id INT,
    salary INT,
    department VARCHAR(50)
)
Truncate table Employees
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('1', 'Alice', NULL, '12000', 'Executive')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('2', 'Bob', '1', '10000', 'Sales')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('3', 'Charlie', '1', '10000', 'Engineering')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('4', 'David', '2', '7500', 'Sales')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('5', 'Eva', '2', '7500', 'Sales')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('6', 'Frank', '3', '9000', 'Engineering')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('7', 'Grace', '3', '8500', 'Engineering')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('8', 'Hank', '4', '6000', 'Sales')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('9', 'Ivy', '6', '7000', 'Engineering')
insert into Employees (employee_id, employee_name, manager_id, salary, department) values ('10', 'Judy', '6', '7000', 'Engineering')

分析

①使用recursive进行递归查询 通过引用 CTE 自身不断生成新的结果集,直到满足终止条件主表 employee_id 和 子表manager_id 连接条件 直到employee_id遍历完  通过子表employee_id 记录路径,level记录层级 

with recursive t1 as (select employee_id,
                             employee_name,
                             1                         as level,
                             CAST(employee_id AS CHAR) as path,
                             salary,
                             department,
                             manager_id
                      from Employees
                      where manager_id is null
                      union
                      select t2.employee_id,
                             t2.employee_name,
                             1 + t1.level,
                             concat(t1.path, ',', t2.employee_id) as path,
                             t2.salary,
                             t2.department,
                             t2.manager_id
                      from Employees t2
                               join t1
                                    on t2.manager_id = t1.employee_id)
select * from t1

②根据路径 展开主表和子表 将主表employee_id下的所有子员工都展开

select e.employee_id as m_id, e2.employee_id, e2.salary
         from t1 e
                  join t1 e2 on e2.path like concat(e.path, '%')

③根据主employee_id  计算team_size团队人数和budget预算

select m_id, (count(m_id) - 1) as team_size, sum(salary) as budget
         from t3
         group by m_id

④将结果进行连接 排序

代码
with recursive t1 as (select employee_id,
                             employee_name,
                             1                         as level,
                             CAST(employee_id AS CHAR) as path,
                             salary,
                             department,
                             manager_id
                      from Employees
                      where manager_id is null
                      union
                      select t2.employee_id,
                             t2.employee_name,
                             1 + t1.level,
                             concat(t1.path, ',', t2.employee_id) as path,
                             t2.salary,
                             t2.department,
                             t2.manager_id
                      from Employees t2
                               join t1
                                    on t2.manager_id = t1.employee_id)
# select * from t1
   , t3 as (select e.employee_id as m_id, e2.employee_id, e2.salary
            from t1 e
                     join t1 e2 on e2.path like concat(e.path, '%'))
   , t4 as (select m_id, (count(m_id) - 1) as team_size, sum(salary) as budget
            from t3
            group by m_id)
select employee_id, employee_name, level, team_size, budget
from t1
         left join t4 on employee_id = m_id
order by level, budget desc, employee_name;

-- 合并
with recursive employee as
                   (select employee_id, employee_name, manager_id, salary, 1 as level, cast(employee_id as char) as path
                    from Employees
                    where manager_id is null
                    union
                    select e2.employee_id,
                           e2.employee_name,
                           e2.manager_id,
                           e2.salary,
                           1 + employee.level,
                           concat(employee.path, ',', e2.employee_id)
                    from Employees e2
                             join employee on
                   e2.manager_id = employee.employee_id)
# select * from
, t3 as(
    select e1.employee_id ,e2.employee_id as emp,e1.employee_name,e1.level,e2.salary from employee e1 left join employee e2 on  e2.path like concat(e1.path,'%')
)
select employee_id,employee_name,level,(count(employee_id)-1) as team_size,sum(salary)'budget'  from t3
group by employee_id, employee_name,level
order by level,budget desc,employee_name
;
总结

①递归查询基本结构

WITH RECURSIVE cte_name (column_list) AS (
    -- 锚成员(初始查询)
    SELECT ...
    UNION [ALL]
    -- 递归成员(递归查询)
    SELECT ...
)
SELECT * FROM cte_name;
  • 锚成员:返回初始结果集。
  • 递归成员:通过引用 CTE 自身不断生成新的结果集,直到满足终止条件。

②执行顺序分析

递归查询的执行遵循 迭代模型,步骤如下:

步骤 1:执行锚成员
  • 锚查询首先执行,生成递归的基础结果集(R0)。
步骤 2:执行递归成员
  • 将递归成员应用于上一次迭代的结果集(初始为 R0),生成新的结果集(R1)。
  • 去重处理:如果使用 UNION(而非 UNION ALL),会自动删除重复行。
步骤 3:检查终止条件
  • 如果新生成的结果集(R1)为空,递归终止。
  • 否则,将 R1 作为下一次迭代的输入,重复步骤 2。
步骤 4:合并所有结果
  • 递归终止后,将所有迭代的结果集合并(隐式使用 UNION ALL),返回最终结果。

③ 强转为字符串才可以进行拼接

 cast(employee_id as char)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2376461.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不用服务器转码,Web端如何播放RTSP视频流?

在物联网、智慧城市、工业互联网等新兴技术浪潮下,实时视频流(如RTSP协议)作为安防监控、生产巡检、远程协作等场景的核心数据载体,其价值愈发凸显。然而,一个长期困扰行业的痛点始终存在——‌如何在Web浏览器中直接播…

如何开发一款 Chrome 浏览器插件

Chrome是由谷歌开发的网页浏览器,基于开源软件(包括WebKit和Mozilla)开发,任何人都可以根据自己需要使用、修改或增强它的功能。Chrome凭借着其优秀的性能、出色的兼容性以及丰富的扩展程序,赢得了广大用户的信任。市场…

GitHub打开缓慢甚至失败的解决办法

在C:\Windows\System32\drivers\etc的hosts中增加如下内容: 20.205.243.166 github.com 199.59.149.236 github.global.ssl.fastly.net185.199.109.153 http://assets-cdn.github.com 185.199.108.153 http://assets-cdn.github.com 185.199.110.153 http://asset…

18前端项目----Vue项目收尾优化|重要知识

收尾/知识点汇总 项目收尾二级路由未登录全局路由守卫路由独享守卫图片懒加载路由懒加载打包上线 重要知识点汇总组件通信方式1. props2. 自定义事件3. 全局事件总线4. 订阅与发布pubsub5. Vuex6. 插槽 sync修饰符attrs和listeners属性children和parent属性mixin混入作用域插槽…

仿RabbitMQ 模拟实现消息队列

文章目录 项目项目介绍开发环境技术选型 开始项目前第三方框架内容介绍muduo搭建服务端,客户端服务端:客户端:makefile muduo库protobuf通信服务端:客户端 sqlitegtest线程池future 认识,async使用promis使用package_t…

基于Qt的app开发第八天

写在前面 笔者是一个大一下计科生,本学期的课程设计自命题完成一个督促学生自律的打卡软件,目前已经完成了待办和打卡部分功能,本篇要完成规划板块不需要存储就能实现的功能 需求分析 这一板块内容相比前两个板块还有一些特殊,因…

数据分析-图2-图像对象设置参数与子图

from matplotlib import pyplot as mp mp.figure(A figure,facecolorgray) mp.plot([0,1],[1,2]) mp.figure(B figure,facecolorlightgray) mp.plot([1,2],[2,1]) #如果figure中标题已创建,则不会新建窗口, #而是将旧窗口设置为当前窗口 mp.figure(A fig…

查询公网IP地址的方法:查看自己是不是公网ip,附内网穿透外网域名访问方案

本地搭建服务并提供互联网连接时,较为传统的方法是使用公网IP地址。因此,如何查询本地自己是不是公网IP,是必须要掌握的一种技巧。当面对确实无公网IP时,则可以通过内网穿透方案,如nat123网络映射工具,将本…

Redis学习打卡-Day1-SpringDataRedis、有状态无状态

Redis的Java客户端 Jedis 以 Redis 命令作为方法名称,学习成本低,简单实用。Jedis 是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此推荐使用 Jedis 连接池代替Jedis的直连方式。 lettuce Lettuce是基于Netty实现的&am…

Spring Spring Boot 常用注解整理

Spring & Spring Boot 常用注解整理 先理解核心概念:什么是注解(Annotation)?第一部分:IOC(控制反转)和 DI(依赖注入)1. Component2. Service, Repository, Controll…

c#建筑行业财务流水账系统软件可上传记账凭证财务管理系统签核功能

# financial_建筑行业 建筑行业财务流水账系统软件可上传记账凭证财务管理系统签核功能 # 开发背景 软件是给岳阳客户定制开发一款建筑行业流水账财务软件。提供工程签证单、施工日志、人员出勤表等信息记录。 # 财务管理系统功能描述 1.可以自行设置记账科目,做凭…

让 Cursor 教我写 MCP Client

文章目录 1. 写在最前面2. 动手实现一个 MCP Client2.1 How 天气查询 Client2.1.1 向 Cursor 提问的艺术2.1.2 最终成功展示2.1.3 client 的代码 3. MCP 协议核心之一总结3.1 SSE vs WebSocket 4. 碎碎念5. 参考资料 1. 写在最前面 学习了 MCP Server 的实现后,刚好…

反射, 注解, 动态代理

文章目录 单元测试什么是单元测试咱们之前是如何进行单元测试的? 有啥问题 ?现在使用方法进行测试优点Junit单元测试的使用步骤删除不需要的jar包总结 反射认识反射、获取类什么是反射反射具体学什么?反射第一步:或者Class对象 获…

vue vite 无法热更新问题

一、在vue页面引入组件CustomEmployeesDialog,修改组件CustomEmployeesDialog无法热更新 引入方式: import CustomEmployeesDialog from ../dialog/customEmployeesDialog.vue 目录结构: 最后发现是引入import时,路径大小写与目…

深度学习中的查全率与查准率:如何实现有效权衡

📌 友情提示: 本文内容由银河易创AI(https://ai.eaigx.com)创作平台的gpt-4-turbo模型辅助生成,旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证,建议读者通过官方文档或实践进一步确认…

Windows玩游戏的时候,一按字符键就显示桌面

最近打赛伯朋克 2077 的时候,不小心按错键了,导致一按字符键就显示桌面。如下: 一开始我以为是输入法的问题(相信打游戏的人都知道输入法和奔跑键冲突的时候有多烦),但是后来解决半天发现并不是。在网上搜…

Gemini 2.5 Flash和Pro预览版价格以及上下文缓存的理解

Gemini 2.5 Flash和Pro预览版价格 Gemini 2.5 Flash 预览版就是 Google 的最新 AI 大模型,能处理巨量内容。可以免费体验,但有次数和功能上的限制;付费层级才开放全部高级功能。价格也比传统 API 略有不同,尤其在“思考预算”“上…

vue2 头像上传+裁剪组件封装

背景:最近在进行公司业务开发时,遇到了头像上传限制尺寸的需求,即限制为一寸证件照(宽295像素,高413像素)。 用到的第三方库: "vue-cropper": "^0.5.5" 完整组件代码&…

AI-02a5a5.神经网络-与学习相关的技巧-权重初始值

权重的初始值 在神经网络的学习中,权重的初始值特别重要。实际上,设定什么样的权重初始值,经常关系到神经网络的学习能否成功。 不要将权重初始值设为 0 权值衰减(weight decay):抑制过拟合、提高泛化能…

【springcloud学习(dalston.sr1)】Eureka单个服务端的搭建(含源代码)(三)

该系列项目整体介绍及源代码请参照前面写的一篇文章【springcloud学习(dalston.sr1)】项目整体介绍(含源代码)(一) 这篇文章主要介绍单个eureka服务端的集群环境是如何搭建的。 通过前面的文章【springcloud学习(dalston.sr1)】…