查找每个公司的员工薪水中位数
题目来源:Leetcode
Employee表包括所有员工。包含三列:员工Id, 公司名和薪水
思路: 如果是奇数长度,那么 大于中位数的个数 = 小于中位数的个数
解答:(解题思路来自leetcode评论)
SELECT a.Id, a.Company, a.Salary
FROM
Employee a,
Employee b
WHERE a.Company = b.Company
GROUP BY a.Company, a.Salary
HAVING SUM(CASE WHEN a.Salary = b.Salary THEN 1 ELSE 0 END) >= ABS(SUM(SIGN(a.Salary - b.Salary)))
ORDER BY a.Id
难点:
SUM(CASE WHEN a.Salary = b.Salary THEN 1 ELSE 0 END) >= ABS(SUM(SIGN(a.Salary - b.Salary)))
解析:
在自连中,a表salary与b表salary相等时为1。即计算a.Salary = b.Salary的个数
SUM(CASE WHEN a.Salary = b.Salary THEN 1 ELSE 0 END)
SIGN(): 正数取1,负数取-1,0取0
ABS(SUM(SIGN(a.Salary - b.Salary)))
即,
a.Salary > b.Salary --> 1
a.Salary < b.Salary --> -1
a.Salary = b.Salary --> 0
太抽象了,举个栗子:
假设有两组数:奇数列 1,2,3,4,5;偶数列1,2,3,4
① 从小到大排序,1排第一位。
1 = 1 --> 0; 1 < 2 --> -1; 1 < 3 --> -1; 1 < 4 --> -1; 1 < 5 --> -1
奇数:Abs(sum(0-1-1-1-1)) = 4
偶数:Abs(sum(0-1-1-1)) = 3
② 从小到大排序,2排第二位。
2 > 1 --> 1; 2 = 2 --> 0; 2 < 3 --> -1; 2 < 4 --> -1; 2 < 5 --> -1
奇数:Abs(sum(1+0-1-1-1)) = 2
偶数:Abs(sum(1+0-1-1)) = 1
③ 从小到大排序,3排第三位。(我们要找的中位数)
3 > 1 --> 1; 3 > 2 --> 1; 3 = 3 --> 0; 3 < 4 --> -1; 3 < 5 --> -1
奇数:Abs(sum(1+1-0-1-1)) = 0
偶数:Abs(sum(1+1-0-1)) = 1
④ 从小到大排序,4排第四位。
4 > 1 --> 1; 4 > 2 --> 1; 4 > 3 --> 1; 4 = 4 --> 0; 4 < 5 --> -1
奇数:Abs(sum(1+1+1+0-1)) = 2
偶数:Abs(sum(1+1+1+0)) = 3
⑤ 从小到大排序,5排第五位。
5 > 1 --> 1; 5 > 2 --> 1; 5 > 3 --> 1; 5 > 4 --> 1; 5 = 5 --> 0
奇数:Abs(sum(1+1+1+1+0)) = 4
发现什么规律了吗?
ABS(SUM(SIGN(a.Salary - b.Salary)))
这个计算值,我们可以当成是衡量偏移中间位置的一个程度。越靠近中间位置,得到的数值越小。对于个数为奇数的数组,中位数的偏移值为0。因为大于中位数和小于中位数的个数相等,能够相互抵消。而个数为偶数的数组,中位数的偏移值为1,因为不能够完全抵消。
即,中位数的 ABS(SUM(SIGN(a.Salary - b.Salary))) <= 1
这里可以用SUM(CASE WHEN a.Salary = b.Salary THEN 1 ELSE 0 END)进行限制
得到结果:
优化:中位数取平均值。
欢迎指正!( ᖛ ̫ ᖛ )ʃ)
Good Good Study
Day Day No Hair
与大家共勉!