目录
0 问题描述
1 数据准备
2 数据分析
3 小结
问题:查询每个部门除去最高、最低薪水后的平均薪水,并保留整数。
(1)数据
雇员编号 | 部门编号 | 薪水 |
10001 | 1 | 60117 |
10002 | 2 | 92102 |
10003 | 2 | 86074 |
10004 | 1 | 66596 |
10005 | 1 | 66961 |
10006 | 2 | 81046 |
10007 | 2 | 94333 |
10008 | 1 | 75286 |
10009 | 2 | 85994 |
10010 | 1 | 76884 |
(2)建表SQL
drop table if exists dan_test.salary
CREATE TABLE dan_test.salary (
emp_num string ,
dep_num string ,
salary string
)
ROW format delimited FIELDS TERMINATED BY ",";
(3)加载数据
load data local inpath "/home/centos/dan_test/salary.txt" into table salary;
(4) 查询数据
目标:需要查询每个部门除去最高、最低薪水后的平均薪水,并保留整数。
三个关键点信息:
思路1:找出部门中最高、最低薪水并进行过滤。采用窗口函数row_number()对按部门分组,薪水排序后的数据进行标记
SQL如下:
select emp_num
,dep_num
,salary
,row_number() over(partition by dep_num order by salary) as rn1 --标记最小
,row_number() over(partition by dep_num order by salary desc) rn2 --标记最大
from salary
查询结果如下:
根据需求,过滤出中间结果,即rn1 >1 和rn2 >1 条件同时成立。当存在多个窗口结果集,且显示的字段参与窗口运算,则该字段以最后一个窗口函数为准,如本题salary显示结果是以最后一个窗口结果显示的。 最终SQL如下
select *
from(
select emp_num
,dep_num
,salary
,row_number() over(partition by dep_num order by salary) as rn1 --标记最小
,row_number() over(partition by dep_num order by salary desc) rn2 --标记最大
from salary
) t
where rn1 > 1 and rn2 > 1
思路2:为了过滤最大、最小,我们可以只进行一次排序,先求出分组总行数,然后对salary进行分组升序排序,那么我们需要的结果就是,1 最终过滤出需要的结果如下: 求得最终平均值的SQL如下: 计算结果如下: 方法3:公式法。按照求平均值的正常思路:(sum(salary)-max(salary) -min(salary)) / count(salary) -2 --按照部门分组。 (1)先按每个部门求最大薪水值、最小薪水值、薪水值总和总次数。具体SQL如下: 求的结果如下: (2)求每个部门去除最大、最小值后的平均值 (公式法)。 此时按照部门进行分组后,由于未在分组中的字段的获取必须放在聚合函数中才能被使用,因而我们采用max()函数来获取其余字段,但会不会影响结果呢?其实是不会影响的,因为上一步的结果返回值都是聚合过后的,每个部门只有一条数据,每个字段也只有一个值,因而你无论使用了max(),min(),sum()等函数其结果都是一样的。这也是一种技巧,当分组后如果这一组中只有一个值时,为了提取该字段值,我们可以使用max(),min()函数进行提取,聚合函数往往也具有过滤NULL值的作用,利用这一特性,在写SQL时往往为上层查询提供了很多便利。 最终的SQL 如下: 最终结果如下: 本文使用的知识点总结:select emp_num
,dep_num
,salary
,count(1) over(partition by dep_num) as cn --求出总行数
,row_number() over(partition by dep_num order by salary ) rn --按照薪水升序排序
from salary
select *
from(
select emp_num
,dep_num
,salary
,count(1) over(partition by dep_num) as cn --求出总行数
,row_number() over(partition by dep_num order by salary ) rn --按照薪水升序排序
from salary
) t
where rn > 1 and rn < cn
---方法1
select t.dep_num,round(avg(t.salary),0) as avg_salary
from
(
select *,
row_number() over (partition by dep_num order by salary desc) as rn1,
row_number() over (partition by dep_num order by salary) as rn2
from salary
) t
where t.rn1 > 1 and t.rn2 > 1
group by t.dep_num;
--------方法2
select t.dep_num,round(avg(t.salary),0) as avg_salary
from
(
select emp_num
,dep_num
,salary
,count(1) over(partition by dep_num) as cn --求出总行数
,row_number() over(partition by dep_num order by salary ) rn --按照薪水升序排序
from salary
) t
where t.rn > 1 and t.rn < t.cn
group by t.dep_num;
select
dep_num
,count(salary) as cn --求出总个数
,max(salary) as max_salary --salary最大值
,min(salary) as min_salary --salary最小值
,sum(salary) as sum_salary --salary总和
from salary
group by dep_num
select dep_num
,(max(sum_salary) - max(max_salary) -max(min_salary)) / (max(cn) -2) as avg_salary--使用max()函数提取非group by组中的字段值,供上层计算
from (
select
dep_num
,count(salary) as cn --求出总个数
,max(salary) as max_salary --salary最大值
,min(salary) as min_salary --salary最小值
,sum(salary) as sum_salary --salary总和
from salary
group by dep_num
) t
group by dep_num
3 小结