You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
select id, company, salary from (
select
id, company, salary,
row_number() over(partition by company order by salary) as 排名,
count(id) over(partition by company) as total
from employee
) as temp
where temp.排名 in (floor((total +1) /2), floor((total +2) /2));
筛选条件也可以使用 where 排名 >= total / 2 and 排名 <= total / 2 + 1
当 total = 6,中位数是 3 和 4 , 排名 ≥ 3 and 排名 ≤ 4 ,筛选出来的是 3 和 4
当 total = 5,中位数是 3 , 排名 ≥ 2.5 and 排名 ≤ 3.5 ,筛选出来的就是 3
SQL:方法二
select id, company, salary from (
select
id,
company,
salary,
if(@prev = company, @r:=@r+1, @r:=1) as 排名,
@prev:=company
from employee, (select @r:=0, @prev:=0) init,
order by company, salary, id
) as temp1 join (
selectcount(*) as total, company from employee group by company
) as temp2 using(company) where 排名 >= total /2and 排名 <= total /2+1;
解析
和方法一的思路一样,这里是用变量来实现 salary 排名
SQL:方法三
with temp as (
selecte1.idfrom employee e1 join employee e2 using(company)
group bye1.idhavingsum(e1.salary>=e2.salary) >=count(e1.id) /2andsum(e1.salary<=e2.salary) >=count(e1.id) /2
)
select id, company, salary from employee where exists (
select id from temp whereemployee.id=temp.id
);
解析
**思路:**将每个人和公司的其他所有人一一比较,将 employee 通过 company 自连,并且按照 e1.id 进行分组
筛选:
sum(e1.salary >= e2.salary) >= count(e1.id) / 2
以 A 公司为例, A 公司有 6 名员工,所以通过 company 连接后,一共有 36 条数据,因为每一条数据都要和自身进行连接,如下图所示。
selectsum(e1.salary>=e2.salary),
count(e1.id),
e1.id,
any_value(e1.salary),
any_value(e1.company),
any_value(e2.id),
any_value(e2.salary),
any_value(e2.company)
from employee e1 join employee e2 using(company)
group bye1.id
SQL:方法四
select
any_value(e1.id) as id,
e1.companyas company,
e1.salaryas salary
from employee e1 left join employee e2 using(company)
group bye1.company, e1.salaryhavingsum(
case when e1.salary=e2.salary then 1 else 0 end
) >= abs(sum(sign(e1.salary-e2.salary)))
order by id;
解析
**思路:**将每个人和公司的其他所有人一一比较,将 employee 通过 company 自连,并且按照 e1.company 和 e1.salary 进行分组
筛选:
sum(case when e1.salary = e2.salary then 1 else 0 end)
sum(case when e1.salary = e2.salary then 1 else 0 end) >= abs(sum(sign(e1.salary - e2.salary))) 这里用 >= 是因为如果有几个人工资相等时 sum(case when e1.salary = e2.salary then 1 else 0 end) 会大于工资相等的人数
通过将 sum(case when e1.salary = e2.salary then 1 else 0 end) 和sum(sign(e1.salary - e2.salary)) 查询出来,理清思路
selectsum(case when e1.salary=e2.salary then 1 else 0 end),
sum(sign(e1.salary-e2.salary)),
any_value(e1.id) as id,
e1.companyas company,
e1.salaryas salary,
any_value(e2.id),
any_value(e2.company),
any_value(e2.salary)
from employee e1 left join employee e2 using(company)
group bye1.company, e1.salaryorder by id;
The text was updated successfully, but these errors were encountered:
题目
查找每个公司的薪水中位数(需要不使用内置函数)
SQL:方法一
解析
row_number()
计算排名,并按照company
分组,salary
升序company
分组,并计算总数floor((total + 1) / 2)
和floor((total + 2) / 2)
,floor
是想下取整total = 6
,中位数是3
和4
,这里计算的结果正是3
和4
total = 5
,中位数是3
,这里计算的两个值分别是3
和3
where 排名 >= total / 2 and 排名 <= total / 2 + 1
total = 6
,中位数是3
和4
,排名 ≥ 3 and 排名 ≤ 4
,筛选出来的是3
和4
total = 5
,中位数是3
,排名 ≥ 2.5 and 排名 ≤ 3.5
,筛选出来的就是3
SQL:方法二
解析
和方法一的思路一样,这里是用变量来实现
salary
排名SQL:方法三
解析
**思路:**将每个人和公司的其他所有人一一比较,将
employee
通过company
自连,并且按照e1.id
进行分组筛选:
sum(e1.salary >= e2.salary) >= count(e1.id) / 2
A
公司为例,A
公司有6
名员工,所以通过company
连接后,一共有36
条数据,因为每一条数据都要和自身进行连接,如下图所示。group by e1.id
分组后,就去掉了重复的e1.id
sum(e1.salary >= e2.salary)
将e1.id.salary
和每个e2.id.salary
比较,计算出e1.id.salary
大于等于e2.id.salary
的有几个e1.id
分组,所以count(e1.id)
计算出有多少个id
,也就是说和几个人进行比较(或者说是公司的总人数)salary(e1.salary <= e2.salary) >= count(e1.id) / 2
sum(...)
这步计算的就比总人数的一半要大于,也就是sum(...) > count(e1.id) / 2
sum(...)
这步计算的就比总人数的一半要小于,也就是sum(...) < count(e1.id) / 2
sum(...)
这步计算的就等于总人数的一半,也就是sum(...) = count(e1.id) / 2
Tips
无法去除最后重复的中位数,因为这里是按照员工
id
进行分组的。在
MySQL 8.0
中使用group by
需要和select
的字段一致,所以当要查看连接后表中其他字段时,可以用any_value()
理不清思路时可以把筛选条件放到
select
中,查询出来在比对自己的思路,比如说sum(e1.salary >= e2.salary)
和count(e1.id)
SQL:方法四
解析
**思路:**将每个人和公司的其他所有人一一比较,将
employee
通过company
自连,并且按照e1.company
和e1.salary
进行分组筛选:
sum(case when e1.salary = e2.salary then 1 else 0 end)
abs(sum(sign(e1.salary - e2.salary)))
sign
用来确定一个数是正数、负数、还是零,这里以A
公司的id = 1
的员工为例e1.salary=2341
,e2.salary=451
,sign(e1.salary-e2.salary)
结果为1
e1.salary=2341
,e2.salary=15314
,sign(e1.salary-e2.salary)
结果为-1
e1.salary=2341
,e2.salary=15
,sign(e1.salary-e2.salary)
结果为1
e1.salary=2341
,e2.salary=341
,sign(e1.salary-e2.salary)
结果为1
e1.salary=2341
,e2.salary=2341
,sign(e1.salary-e2.salary)
结果为0
e1.salary=2341
,e2.salary=513
,sign(e1.salary-e2.salary)
结果为1
sum()
对上面的sign(...)
进行求和为4
abs()
求出sum(...)
的绝对值sign(e1.salary-e2.salary)
大于1
sign(e1.salary-e2.salary)
小于1
sign(e1.salary-e2.salary)
等于1
(ps:如果有几个人的工资相等,并且是中位数,那么这里1
就是对应的工资相等的人数)order by id
对id
进行升序排序Tips
sum(case when e1.salary = e2.salary then 1 else 0 end) >= abs(sum(sign(e1.salary - e2.salary)))
这里用>=
是因为如果有几个人工资相等时sum(case when e1.salary = e2.salary then 1 else 0 end)
会大于工资相等的人数sum(case when e1.salary = e2.salary then 1 else 0 end)
和sum(sign(e1.salary - e2.salary))
查询出来,理清思路The text was updated successfully, but these errors were encountered: