中位数求法的思路

**思路**:对于一个数组中的中位数, 1. **大于该数的数值个数**与**小于该数的数值个数$\geq$(总数个数/2)**; 2. 当数组从<font color=red>0</font>开始排序时,又可以说该数的大小排名位于 **[ floor(数组最大排名-1)/2, ceil(数组最大排名-1)/2 ]之间** ; 当数组从<font color=red>1</font>开始排序时,又可以说该数的大小排名位于 **[ floor(数组最大排名+1)/2, ceil(数组最大排名+1)/2 ]之间** - 当数组为**奇数**时,满足条件的数字只有一个 - 当数组为**偶数**时,满足条件的数字有两个 - 因此,只要将得到的一个或两个数字取**平均值**即可 --- # 571. 给定数字的频率查询中位数(难度:<font color=red>**困难**</font>) Numbers 表保存数字的值及其频率 ![批注 20200830 111150.png](https://cos.easydoc.net/17082933/files/kegjkj66.png) 在此表中,数字为 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 3 ,所以中位数 是 (0 + 0) / 2 = 0 。 ![批注 20200830 111150.png](https://cos.easydoc.net/17082933/files/kegjl46b.png) 请编写一个查询来查找所有数字的中位数并将结果命名为 median 。 **解法:** - **利用中位数性质** ```sql select avg(n) as median from ( select Number as n, @c1 + 1 as 'c1', (@c1 := @c1 + Frequency) as 'c2', t2.s from Numbers, (select @c1 := 0) t1, ( select sum(Frequency) as s from Numbers ) t2 order by n ) tmp where c1 <= s/2 + 1 and c2 >= s/2 ``` --- # 569. 员工薪水中位数(难度:<font color=red>**困难**</font>) Employee 表包含所有员工。 Employee 表有三列:员工Id,公司名和薪水。 ![批注 20200830 111150.png](https://cos.easydoc.net/17082933/files/kegjy6kj.png) 请编写SQL查询来查找每个公司的薪水中位数。挑战点:你是否可以在不使用任何内置的SQL函数的情 况下解决此问题。 ![image.png](https://cos.easydoc.net/17082933/files/kegjynk1.png) 注:这题偶数数组它的中位数取了两个 **解法:** **(1)变量法** ```sql select e.Id,e.Company,e.Salary from ( select id, company,salary, if(@pre=company,@rank:=@rank+1,@rank:=0) 'rank', @pre:=company from ( select * from employee order by company,salary,id) e1 , (select @pre:=null,@rank:=-1) temp ) e inner join ( select company, count(*) 'max' from employee group by Company ) e1 on e.company=e1.company where e.rank in(floor((e1.max-1)/2),ceil((e1.max-1)/2)); ``` **(2)子查询** - 运用CASE表达式,非等值自连接和HAVING子句来找中位数 - 通过 WHERE e1.Company = e2.Company 进行分组 - 最后通过GROUP BY 去重 ```sql select Id, Company, Salary from Employee where Id in ( select e1.Id from Employee e1, Employee e2 WHERE e1.Company = e2.Company GROUP BY e1.Id HAVING SUM ( CASE WHEN e1.Salary >= e2.Salary THEN 1 ELSE 0 END) >= COUNT(*)/2 AND SUM( CASE WHEN e1.Salary <= e2.Salary THEN 1 ELSE 0 END) >= COUNT(*)/2 ) GROUP BY Company, Salary ORDER BY Company ```