目录

  • 一、题目
  • 二、解决
    • 1、窗口函数
    • 2、自关联后分组筛选
  • 三、参考

一、题目

表: Employee

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| id           | int     |
| company      | varchar |
| salary       | int     |
+--------------+---------+
Id是该表的主键列。
该表的每一行表示公司和一名员工的工资。

写一个SQL查询,找出每个公司的工资中位数。

任意顺序 返回结果表。

查询结果格式如下所示。

示例 1:

输入:
Employee 表:
+----+---------+--------+
| id | company | salary |
+----+---------+--------+
| 1  | A       | 2341   |
| 2  | A       | 341    |
| 3  | A       | 15     |
| 4  | A       | 15314  |
| 5  | A       | 451    |
| 6  | A       | 513    |
| 7  | B       | 15     |
| 8  | B       | 13     |
| 9  | B       | 1154   |
| 10 | B       | 1345   |
| 11 | B       | 1221   |
| 12 | B       | 234    |
| 13 | C       | 2345   |
| 14 | C       | 2645   |
| 15 | C       | 2645   |
| 16 | C       | 2652   |
| 17 | C       | 65     |
+----+---------+--------+
输出:
+----+---------+--------+
| id | company | salary |
+----+---------+--------+
| 5  | A       | 451    |
| 6  | A       | 513    |
| 12 | B       | 234    |
| 9  | B       | 1154   |
| 14 | C       | 2645   |
+----+---------+--------+

进阶: 你能在不使用任何内置函数或窗口函数的情况下解决它吗?

二、解决

1、窗口函数

思路:

S1:使用 row_number() 计算排名,并按照 company 分组并计算总数
S2:筛选出中位数,条件 floor((total + 1) / 2)floor((total + 2) / 2)

  • 当 total = 6,中位数是 3 和 4 ,这里计算的结果正是 3 和 4
  • 当 total = 5,中位数是 3,这里计算的两个值分别是 3 和 3

代码-版本1:

# 超 98%
SELECTId AS id,Company AS company,Salary AS salary
FROM(SELECTId,Company,Salary,COUNT(*) OVER(PARTITION BY Company) AS cnt,ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Salary, Id) AS ranking1,ROW_NUMBER() OVER(PARTITION BY Company ORDER BY Salary DESC, Id DESC) AS ranking2FROMEmployee) t1
WHEREROUND(cnt / 2, 0) <= ranking1
ANDROUND(cnt / 2, 0) <= ranking2
ORDER BYCompany,Salary,Id;

补充:中位数代码实现部分解释

    ROUND(cnt / 2, 0) <= ranking1
ANDROUND(cnt / 2, 0) <= ranking2

代码-版本2:

# 超5%
select id, company, salary from (selectid, company, salary,row_number() over(partition by company order by salary) as 排名,count(id) over(partition by company) as totalfrom employee
) as temp
where temp.排名 in (floor((total + 1) / 2), floor((total + 2) / 2));
# where 排名 >= total / 2 and 排名 <= total / 2 + 1

2、自关联后分组筛选

思路:

将每个人和公司的其他所有人一一比较,将 employee 通过 company 自连,并且按照 e2.company 和 e2.salary 进行分组。

代码-版本1:

# 超5%
select t1.Id as id, t1.Company as company, t1.Salary as salary
from Employee t2, Employee t1 # t2在前
where t1.Company = t2.Company
group by t1.Company, t1.Salary
having  sum(case when t1.Salary = t2.Salary then 1 else 0 end)   # 自己和自己比较的个数>= abs( sum( sign(t1.Salary - t2.Salary) ) )  # 大于自己个数 与 小于自己个数 的差值
order by t1.Company asc, t1.Salary asc, t1.Id asc;

理解:

# 核心代码:
sum(case when t1.Salary = t2.Salary then 1 else 0 end)   # 自己和自己比较的个数
>=
abs( sum( sign(t1.Salary - t2.Salary) ) )  # 大于自己个数 与 小于自己个数 的差值


abs(sum(sign(e1.salary - e2.salary)))sign() 可以确定一个数是正数、负数或零,以 A 、C公司为例。

  • A公司:一般,偶数情况下中位数的差值abs(sum(sign(e1.salary-e2.salary)))为1,距离越远,差值越大。
e1.salary e2.salary sign(e1.salary-e2.salary) 结果 case when t1.Salary = t2.Salary then 1 else 0 end
15 15 0 1
341 15 1 0
451 15 1 0
513 15 1 0
2341 15 1 0
15314 15 1 0
- - abs(sum(*))=5 abs(sum(*))=1
- - - -
15 341 -1 0
341 341 0 1
451 341 1 0
513 341 1 0
2341 341 1 0
15314 341 1 0
- - abs(sum(*))=3 abs(sum(*))=1
- - - -
15 451 -1 0
341 451 -1 0
451 451 0 1
513 451 1 0
2341 451 1 1
15314 451 1 0
- - abs(sum(*))=1 abs(sum(*))=1
- - - -
15 513 -1 0
341 513 -1 0
451 513 -1 0
513 513 0 1
2341 513 1 0
15314 513 1 0
- - abs(sum(*))=1 abs(sum(*))=1
- - - -
15 2341 -1 0
341 2341 -1 0
451 2341 -1 0
513 2341 -1 0
2341 2341 0 1
15314 2341 1 0
- - abs(sum(*))=3 abs(sum(*))=1
- - - -
15 15314 -1 0
341 15314 -1 0
451 15314 -1 0
513 15314 -1 0
2341 15314 -1 0
15314 15314 0 1
- - abs(sum(*))=5 abs(sum(*))=1
- - - -
  • B公司( 删除| 7 | B | 15 | ):一般,奇数情况下中位数的差值abs(sum(sign(e1.salary-e2.salary)))为0,距离越远,差值越大。
e1.salary e2.salary sum(abs(sign(e1.salary-e2.salary))) case when t1.Salary = t2.Salary then 1 else 0 end
13 -4 1
234 -2 1
1154 0 1
1221 2 1
1345 4 1
  • C公司:中位数重复情况,相同中位数个数增加,其他不变。
e1.salary e2.salary sign(e1.salary-e2.salary) 结果 case when t1.Salary = t2.Salary then 1 else 0 end
65 65 0 1
2345 65 1 0
2645 65 1 0
2645 65 1 0
2652 65 1 0
- - abs(sum(*))=4 abs(sum(*))=1
- - - -
65 2345 -1 0
2345 2345 0 1
2645 2345 1 0
2645 2345 1 0
2652 2345 1 0
- - abs(sum(*))=2 abs(sum(*))=1
- - - -
65 2645 -1 0
2345 2645 -1 0
2645 2645 0 1
2645 2645 0 1
2652 2645 1 0
- - abs(sum(*))=1 abs(sum(*))=2
- - - -
65 2645 -1 0
2345 2645 -1 0
2645 2645 0 1
2645 2645 0 1
2652 2645 1 0
- - abs(sum(*))=1 abs(sum(*))=2
- - - -
65 2652 -1 0
2345 2652 -1 0
2645 2652 -1 0
2645 2652 -1 0
2652 2652 0 1
- - abs(sum(*))=4 abs(sum(*))=1
- - - -

可以通过下面的SQL对上面的结果进行验证:

selecte1.id as e1_id,e1.company as e1_company,e1.salary as e1_salary,e2.id as e2_id,e2.company as e2_company,e2.salary as e2_salary,sum(case when e1.salary = e2.salary then 1 else 0 end) as selfCnt,  # 自己和自己比较的个数sum(sign(e1.salary - e2.salary)) as moreSubLess   # 大于自己个数 与 小于自己个数 的差值
from employee e1 left join employee e2 using(company)
group by e1.company, e1.salary
order by e1.id;
# 可略 - any_value():选择被分到同一组的数据里第一条数据的指定列值作为返回数据。
selectsum(case when e1.salary = e2.salary then 1 else 0 end),sum(sign(e1.salary - e2.salary)),any_value(e1.id) as id
from employee e1 left join employee e2 using(company)
group by e1.company, e1.salary
order by id;

三、参考

1、四种方法解员工薪水中位数
2、简洁窗口函数排序
3、MySQL + 开窗函数
4、any_value()函数

【LeetCode-SQL】569. 员工薪水中位数相关推荐

  1. LeetCode MySQL 569. 员工薪水中位数(over窗口函数)

    文章目录 1. 题目 2. 解题 1. 题目 Employee 表包含所有员工.Employee 表有三列:员工Id,公司名和薪水. +-----+------------+--------+ |Id ...

  2. 【每日SQL打卡】​​​​​​​​​​​​​​​DAY 4丨员工薪水中位数【难度困难】

     活动介绍: 「数据仓库技术交流群」已经正式启动每日SQL打卡,帮助大家扎实基础,努力工作之余,别忘了自我提升. 欢迎报名和邀请小伙伴参与,一个人可能走得很快,但一群人会走得很远.

  3. [SQL实战]之获取所有部门中当前员工薪水最高的相关信息

    题目描述 获取所有部门中当前员工薪水最高的相关信息,给出dept_no, emp_no以及其对应的salary CREATE TABLE dept_emp ( emp_no int(11) NOT N ...

  4. 牛客 SQL:获取每个部门中当前员工薪水最高的相关信息

    题目:获取每个部门中当前员工薪水最高的相关信息 代码: SELECT de.dept_no, de.emp_no, sa.salary FROM dept_emp AS de INNER JOIN s ...

  5. LeetCode(SQL)难度-中等

    LeetCode(SQL)难度-中等 注:排名知识点(题目1->思路来源于牛客-小数志(公众号)) 连续排名,例如3000,2000,2000,1000排名结果为1-2-3-4,体现同薪不同名, ...

  6. Mysql练习题13- 员工薪水中位数

    需求:请编写SQL查询来查找每个公司的薪水中位数.挑战点:你是否可以在不使用任何内置的SQL函数的情况下解决此问题. 展示效果: Id Company Salary 5 A 451 6 A 513 1 ...

  7. 【持续更新】Leetcode SQL题目全解析(附建表sql)

    Leetcode SQL题目全解析 越前须知(雾) 题目Q & A 175 组合两个表 181 超过经理收入的员工 182 查找重复电子邮箱 183 从不订购的用户 197 上升的温度 511 ...

  8. 台积电全球员工薪酬中位数约46万,CEO约899万;苹果上调日本的 iPhone 售价 ;Vim 9.0 发布|极客头条...

    「极客头条」-- 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧. 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews ...

  9. 谷歌员工年薪中位数近190万元!科技公司年薪排行,哪家强?

    雷科技.腾讯科技 | 报道 据报道,由于美国科技股动荡,导致越来越依靠股权奖励的美国科技巨头的员工薪酬受到影响,但他们的收入依然高于绝大多数行业. 根据各大公司提交给美国证券交易委员会(SEC)的文件 ...

最新文章

  1. Mycat分片规则详解
  2. 特斯拉遇上 CPU:程序员的心思你别猜
  3. 【100题】第五十九题 用C++编写不能被继承的类
  4. if test project can't be opened in devenv
  5. 崩坏3服务器维护多久,崩坏35月28日停服维护多久?4.0版本更新内容汇总[图]
  6. XNA 游戏 运行时编辑器
  7. Ubuntu下安装最新版QQ
  8. 2020山东省计算机专科学校排名,2021山东专科学校排名 最好的高职院校排行榜
  9. Xcode 6.0中彻底关闭ARC
  10. powerdesigner 导出mysql 库,自动生成ER图
  11. Linux下常用的优秀软件
  12. UU跑腿前端中台方案
  13. linux copy 复制文件夹及子文件夹
  14. c++自动抢购_淘宝 2020双十一最新版 全自动做任务软件 超级星秀猫 来了!上车~...
  15. 【论文阅读】RegNet-Designing Network Design Space
  16. 【Vue学习笔记_05】v-on事件监听
  17. Flutter安装后出现HTTP host not reachable.
  18. 求最长递增子序列个数——C++
  19. iOS 模拟各种网络环境
  20. 多平台如何发布文章?

热门文章

  1. N的阶乘末尾有几个零C语言,N的阶乘末尾有多少个零?
  2. 视频交友直播软件源码开发的必备功能讲解
  3. 【PB】TriggerEvent()/Event()/PostEvent()有什么不同
  4. could not execute menu item系统找不到指定的文件
  5. 谷歌搜索突显网站的ICO图标和网址
  6. Homebrew安装与配置(macOS)
  7. Chinajoy现场看点直播 猪厂的厂花逗比范 第五人格手办辣眼睛还想带回家
  8. ubuntu安装pip3一直失败的解决方法
  9. Eclipse创建Maven项目报错处理Could not resolve archetype
  10. 免费的包噪音网站分享