數據分析面試必備——SQL你准備好了嗎?
2019-05-31 17:03
數據分析師的招聘JD你們一定不陌生:
可以說,不是每個數據分析崗都要求python,但是每個數據分析崗都需要會SQL。寫這篇文章是希望幫助還沒有實戰過SQL的小伙伴、或者了解一些SQL語句,但是擔心自己了解的太片面的小伙伴。
這篇文章主要介紹的是:如果想要面試數據分析崗位,最優先需要掌握的SQL技能是哪些呢?讀完本文,你能快速知道:
1、除了select 這種基本的語句,我最應該馬上掌握的SQL語句和知識是什么?
2、面試中SQL題80%都在考察的語法是什么?
3、這些語法應該怎么使用?
本文將從三大塊介紹入門SQL需要掌握的語法和知識,分別是最基礎的選擇(select)和連接(join/union);最常用的函數(distinct/group by/order by等);一些小小的進階技巧(組內排序、取前百分之多少的值、時間函數)。
一、最基本(選數據)
•怎么把數據從表里選出來?
-- 從table_1中選擇a這一列
select a from table_1
•想要的數據在多張表里,想取多個字段,該怎么辦?—— 表連接
-- table_1中有id,age; table_2中有id,sex。想取出id,age,sex 三列信息
-- 將table_1,table_2 根據主鍵id連接起來
select a.id,a.age,b.sex from
(select id,age from table_1) a --將select之后的內容存為臨時表a
join
(select id, sex from table_2) b --將select之后的內容存為臨時表b
on a.id =b.id
在這里先介紹一下幾種join: (敲重點,很容易問的哦)
join :hive的join默認是inner join,找出左右都可匹配的記錄;
left join: 左連接,以左表為准,逐條去右表找可匹配字段,如果有多條會逐次列出,如果沒有找到則是NULL;
right join:右連接,以右表為准,逐條去左表找可匹配字段,如果有多條會逐次列出,如果沒有找到則是NULL;
full outer join:全連接,包含兩個表的連接結果,如果左表缺失或者右表缺失的數據會填充NULL。
每種join 都有on , on的是左表和右表中都有的字段。join 之前要確保關聯鍵是否去重,是不是刻意保留非去重結果。
•兩張表數據的字段一樣,想合並起來,怎么辦?
-- 不去重,合並兩張表的數據
select * from
(
select id from table_1
UNION ALL
select id from table_2
)t;
union和union all 均基於列合並多張表的數據,所合並的列格式必須完全一致。union的過程中會去重並降低效率,union all 直接追加數據。union 前后是兩段select 語句而非結果集。
二、最常用
(不是用這個就是用那個,更有可能多重組合)
為方便大家理解每個函數的作用,先建一個表,后面以這個為示例。
•如果有千萬用戶數據,想知道有多少去重的用戶數?—— 去重 distinct
-- 羅列不同的id
select distinct id from table_1
-- 統計不同的id的個數
select count(distinct id) from table_1
-- 優化版本的count distinct
select count(*) from
(select distinct id from table_1) tb
distinct 會對結果集去重,對全部選擇字段進行去重,並不能針對其中部分字段進行去重。使用count distinct進行去重統計會將reducer數量強制限定為1,而影響效率,因此適合改寫為子查詢。
•想分性別進行統計,看看男女各多少?—— 聚合函數和group by
-- 統計不同性別(F、M)中,不同的id個數
select count(distinct id) from table_1
group by sex
-- 其它的聚合函數例如:max/min/avg/sum
-- 統計最大/最小/平均年齡
select max(age), min(age),avg(age) from
table_1
group by id
聚合函數幫助我們進行基本的數據統計,例如計算最大值、最小值、平均值、總數、求和
•只想查看A公司的男女人數數據?—— 篩選 where/having
-- 統計A公司的男女人數
select count(distinct id) from table_1
where company = 'A'
group by sex
-- 統計各公司的男性平均年齡,並且僅保留平均年齡30歲以上的公司
select company, avg(age) from table_1
where sex = 'M'
group by company
having avg(age)>30;
•希望查詢結果從高到低/從低到高排序?—— 排序 order by
-- 按年齡全局倒序排序取最年邁的10個人
select id,age from table_1 order by age DESC
limit 10
•將數值型的變量轉化為分類型的變量? —— case when 條件函數
-- 收入區間分組
select id,
(case when CAST(salary as float)<50000 Then '0-5萬'
when CAST(salary as float)>=50000 and CAST(salary as float)<100000 then '5-10萬'
when CAST(salary as float) >=100000 and CAST(salary as float)<200000 then '10-20萬'
when CAST(salary as float)>200000 then '20萬以上'
else NULL end
from table_1;
case 函數的格式為(case when 條件1 then value1 else null end), 其中else 可以省,但是end不可以省。
在這個例子里也穿插了一個CAST的用法,它常用於string/int/double型的轉換。
•字符串
1.concat( A, B...)返回將A和B按順序連接在一起的字符串,如:concat('foo', 'bar') 返回'foobar'
select concat('www','.iteblog','.com') from
iteblog;
--得到 www.iteblog.com
\2. split(str, regex)用於將string類型數據按regex提取,分隔后轉換為array。
-- 以","為分隔符分割字符串,並轉化為array
Select split("1,2,3",",")as value_array from table_1;
-- 結合array index,將原始字符串分割為3列
select value_array[0],value_array[1],value_array[2] from
(select split("1,2,3",",")as value_array from table_1 )t
\3. substr(str,0,len) 截取字符串從0位開始的長度為len個字符。
select substr('abcde',3,2) from
iteblog;
-- 得到cd
三、基礎進階
•不想全局排序,需要分組排序?—— row_number()
-- 按照字段salary倒序編號
select *, row_number() over (order by salary desc) as row_num from table_1;
-- 按照字段deptid分組后再按照salary倒序編號
select *, row_number() over (partition by deptid order by salary desc) as rank from table_1;
按照depid分組,對salary進行排序(倒序)
除了row_number函數之外,還有兩個分組排序函數,分別是rank() 和dense_rank()。
rank()排序相同時會重復,總數不會變 ,意思是會出現1、1、3這樣的排序結果;
dense_rank() 排序相同時會重復,總數會減少,意思是會出現1、1、2這樣的排序結果。
row_number() 則在排序相同時不重復,會根據順序排序。
•想要獲取top10%的值?—— percentile 百分位函數
-- 獲取income字段的top10%的閾值
select percentile(CAST (salary AS int),0.9)) as income_top10p_threshold from table_1;
-- 獲取income字段的10個百分位點
select percentile(CAST (salary AS int),array(0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0)) as income_percentiles
from table_1;
•想要對時間字段進行操作?—— 時間函數
-- 轉換為時間數據的格式
select to_date("1970-01-01 00:00:00") as start_time from table_1;
-- 計算數據到當前時間的天數差
select datediff('2016-12-30','2016-12-29');
-- 得到 "1"
to_date函數可以把時間的字符串形式轉化為時間類型,再進行后續的計算;
常用的日期提取函數包括:
year()/month()/day()/hour()/minute()/second()
日期運算函數包括datediff(enddate,stratdate) 計算兩個時間的時間差(day);
date_sub(stratdate,days) 返回開始日期startdate減少days天后的日期。
date_add(startdate,days) 返回開始日期startdate增加days天后的日期。
四、常見筆試/面試題
例:有3個表S,C,SC:
S(SNO,SNAME)代表(學號,姓名)
C(CNO,CNAME,CTEACHER)代表(課號,課名,教師)
SC(SNO,CNO,SCGRADE)代表(學號,課號,成績)
問題:
1,找出沒選過“黎明”老師的所有學生姓名。
2,列出2門以上(含2門)不及格學生姓名及平均成績。
3,既學過1號課程又學過2號課所有學生的姓名。
\1. -- 考察條件篩選
select sname from s where sno not in
( select sno from sc where cno in
(
select distinct cno from c where cteacher='黎明'
)
);
\2. -- 考察聚合函數,條件篩選
select s.sname, avg_grade from s
join
(select sno from sc where scgrade < 60 group by sno having count(*) >= 2) t1
on s.sno = t1.sno
join
(select sno, avg(scgrade) as avg_grade from sc group by sno ) t2
on s.sno = t2.sno;
\3. -- 考察篩選、連接
select sname from
( select sno from sc where cno = 1) a
join
(select sno from sc where cno = 2) b
on a.sno = b.sno
這篇SQL面試和筆試的入門文章,主旨是快速、清晰的把握重點。希望大家都能快快入門SQL~