目录

  • 一、题目
  • 二、解决
    • 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. python mysqldb 清除缓存_Python MySqlDB 增删改数据库
  2. MySql通用二进制版本在Linux(Ubuntu)下安装与开启服务
  3. python 爬虫实例 电影-Python爬虫教程-17-ajax爬取实例(豆瓣电影)
  4. WINDOWS SERVER 2003 之域重命名
  5. 关于Plos one 和 SR
  6. Redhat5.4 系统上部署 MooseFS分布式文件系统的部署
  7. Vue el-input实现动态显示type为textarea的文字数量、剩余字数
  8. PetShop 4.0学习笔记:消息队列MSMQ
  9. 服务器时间修改连接超时时间设置,云服务器连接超时时间设置
  10. 牛客java选择题每日打卡Day9
  11. word尝试打开文件时遇到错误 解决方法
  12. 网络Sniffing原理
  13. SAP中MRP控制者的应用理解
  14. 探索:制药厂系统网络时钟同步(NTP时间同步服务器)
  15. 【项目实战】正确辨析蓝绿部署、金丝雀发布(灰度发布)、滚动发布、A/B测试
  16. 中国蚁剑安装使用教程
  17. 数学问题:导函数的左右极限与函数的左右导数是一回事吗?
  18. Android中使用CoAP协议
  19. kubeadm部署kubernetes-1.12.0 HA集群-ipvs
  20. scrapy_redis分布式爬虫爬取亚马逊图书

热门文章

  1. Java反射基础,代码示例
  2. Matlab使用Plot函数实现数据动态显示方法总结
  3. 深圳龙华携手腾讯云 加快推进区块链先行试验区建设
  4. Google Android SDK开发范例大全(第3版)
  5. Mac超好用的系统清理软件 MacBooster 8
  6. 树莓派环境处理_树莓派开发环境配置
  7. 生鲜店1千斤果蔬赔本甩卖,一个月净赚80万?到底是什么套路?
  8. 烽火HG680-MC-晨星9385芯片-9.0-免拆卡刷固件包
  9. 刚学玩原生JS,自己写了一个小游戏,希望在以后能不断地进步加以改善
  10. PHP游戏服务器之GlobalData组件的运用