位元組跳動面試題:你的平均薪水是多少?
薪水錶中記錄了員工的編號,所在部門編號,和薪水。
查詢出每個部門除去最高、最低薪水後的平均薪水,並保留整數。(位元組跳動面試題)
【解題步驟】
1.如何找出最高、最低薪水?
要求每個部門除去最高、最低薪水後的的平均薪水,所以應該查詢出每個部門的最高、最低工資。
所以需要按每組來排名薪水,既要排名,又要分組的問題,需要用視窗函式來解決。
視窗函式的基本語法如下:
1 <視窗函式> over (partition by <用於分組的列名> 2 order by <用於排序的列名>)
語法中<視窗函式>的位置,可以放以下兩種函式:
1) 專用視窗函式,包括rank, dense_rank, row_number等專用視窗函式。
2) 聚合函式,如sum. avg, count, max, min等
在該題中,我們需要對部門進行分組,並對薪水進行排序:
1 select *, 2 rank() over (partition by 部門編號 3 order by 薪水 desc) as ranking 4 from 薪水錶;
查詢結果如下,因為是降序排列,排名為1的是每個部門的最高薪水。
我們還需要再用一次視窗函式求出每個部門的最低薪水,也就是升序排列時,排名為1的是每個部門的最低薪水
1 select *, 2 rank() over (partition by 部門編號 order by 薪水 desc) as rank_1, 3 rank() over (partition by 部門編號 order by 薪水) as rank_2 4 from 薪水錶;
查詢結果如下。下圖rank_1列數值為1(紅色框)的是每個部門的最高薪水,rank_2列數值為1(藍色框)的是每個部門的最低薪水。
2.如何去掉最高和最低薪水?
用where子句來篩選就可以了,where rank_1 > 1 and rank_2> 1
1 select*, 2 rank() over (partition by 部門編號 order by 薪水 desc) as rank_1, 3 rank() over (partition by 部門編號 order by 薪水) as rank_2 4 from 薪水錶 5 where rank_1 >1 and rank_2 >1;
但是這樣執行會出錯,因為按照sql的執行順序,會先執行from和where子句,最後才執行select子句。
而rank_1和rank_2在select子句中,是最後執行的。所以執行時where子句中的rank_1和rank_2是不存在的。
所以,我們需要將前面的查詢結果作為子查詢後,再用where子句:
1 select * 2 from ( 3 select *, 4 rank() over (partition by 部門編號 order by 薪水 desc) as rank_1, 5 rank() over (partition by 部門編號 order by 薪水) as rank_2 6 from 薪水錶 7 ) as a 8 where a.rank_1 >1 and a.rank_2 >1;
查詢結果如下,此時已經是每個部門去掉最高、最低薪水後的結果了。
3.查詢每個部門除去最高、最低薪水的平均薪水
看到“每個”這樣的問題,要想到用分組(group by),平均薪水使用avg函式。
另外,題目還要求薪水保留整數。保留整數即保留0位小數,可以用format函式:
1 format(N,D) 2 N是要格式化的數字 3 D是要舍入的小數位數。
1 select a.部門編號,format(avg(a.薪水),0) as 平均薪水 2 from 3 ( 4 select *, 5 rank() over (partition by 部門編號 order by 薪水 desc) as rank_1, 6 rank() over (partition by 部門編號 order by 薪水) as rank_2 7 from 薪水錶 8 ) as a 9 where a.rank_1 >1 and a.rank_2 >1 10 group by a.部門編號;
查詢結果如下。
【本題考點】
1.考察解決複雜問題的能力,可以使用邏輯樹分析方法,將複雜問題拆解問簡單的子問題。
2.考查sql的執行順序和子查詢
3.遇到既要分組,又要排名的問題,要想到使用視窗函式
4.考查平均數的計算以及結果保留幾位小數
【舉一反三】
如圖是某班6名同學的成績:
請你寫一個sql語句查詢該6名同學的成績中除去最高、最低分的後的平均分數,並保留2位小數。
1 select format(avg(a.成績),2) as 平均成績 2 from 3 ( 4 select *, 5 rank() over (order by 成績 desc) as rank_1, 6 rank() over (order by 成績) as rank_2 7 from 成績表 8 ) as a 9 where a.rank_1 >1 and a.rank_2 >1;