SQL是用於數據分析和數據處理的最重要的編程語言之一,所以與數據科學相關的工做(例如數據分析師、數據科學家和數據工程師)在面試時總會問到關於 SQL 的問題。面試
SQL面試問題旨在評估應聘者的技術和解決問題的能力。所以對於應聘者來講,關鍵在於不只要根據樣本數據編寫出正確的查詢,並且還要像對待現實數據集同樣考慮各類場景和邊緣狀況。數據庫
在這篇文章中,我將介紹 SQL 面試問題中常見的模式,並提供一些在 SQL 查詢中巧妙處理它們的技巧。編程
1dom
問問題編程語言
要搞定一場 SQL 面試,最重要的是儘可能多問問題,獲取關於給定任務和數據樣本的全部細節。充分理解需求後,接下來你就能夠節省不少迭代問題的時間,而且能很好地處理邊緣狀況。函數
我注意到許多候選人常常還沒徹底理解SQL問題或數據集,就直接開始編寫解決方案了。以後,等我指出他們解決方案中存在的問題後,他們只好反覆修改查詢。最後,他們在迭代中浪費了不少面試時間,甚至可能到最後都沒有找到正確的解決方案。ui
我建議你們在參加SQL面試時,就當成是本身在和業務夥伴共事。因此在你提供解決方案以前,應該要針對數據請求瞭解清楚全部的需求。spa
舉例:查找薪水最高的前 3 名員工。code
樣本employee_salary表blog
這裏你應該要求面試官說清楚「前三名」具體是什麼意思。我應該在結果中包括 3 名員工嗎?你要我怎樣處理關係?此外,請仔細檢查樣本員工數據。salary 字段的數據類型是什麼?在計算以前是否須要清除數據?
2
選哪個JOIN
在SQL中,JOIN 一般用來合併來自多個表的信息。
有四種不一樣類型的 JOIN,但在大多數狀況下,咱們只使用INNER、LEFT和FULLJOIN,由於 RIGHTJOIN並非很直觀,還可使用 LEFTJOIN 很簡單地重寫。在 SQL 面試中,須要根據給定問題的特定要求選擇你要使用的正確JOIN。
舉例:查找每一個學生參加的課程總數。(提供學生 id、姓名和選課的數量。)
樣本student和class_history表
你可能已經注意到了,並不是全部出如今 class_history 表中的學生都出如今了 student 表中,這多是由於這些學生已經畢業了。(這在事務數據庫中其實是很是典型的狀況,由於再也不活躍的記錄每每會被刪除。)
根據面試官是否但願結果中包含畢業生,咱們須要使用LEFT JOIN或 INNER JOIN來組合兩個表:
WITH class_count AS ( SELECT student_id, COUNT(*) AS num_of_class FROM class_history GROUP BY student_id ) SELECT c.student_id, s.student_name, c.num_of_class FROM class_count c -- CASE 1: include only active students JOIN student s ON c.student_id = s.student_id -- CASE 2: include all students -- LEFT JOIN student s ON c.student_id = s.student_id
3
GROUP BY
GROUP BY是SQL中最重要的功能,由於它普遍用於數據聚合。若是在一個 SQL 問題中看到諸如求和、平均值、最小值或最大值之類的關鍵字,這就代表你可能應該在查詢中使用GROUP BY了。
一個常見的陷阱是在GROUP BY過濾數據時混淆 WHERE和HAVING——我見過不少人犯了這個錯誤。
舉例:計算每一個學生在每一個學年的必修課程平均 GPA,並找到每一個學期中符合 Dean’s List(GPA≥3.5)資格的學生。
樣本gpa_history表
因爲咱們在GPA計算中僅考慮必修課程,所以須要使用WHERE is_required=TRUE來排除選修課程。
咱們須要每位學生在每學年的平均GPA,所以咱們將同時GROUP BY student_id和school_year 列,並取gpa列的平均值。最後,咱們只保留學平生均 GPA高於3.5的行,可使用HAVING來實現。合起來是下面這樣:
SELECT student_id, school_year, AVG(gpa) AS avg_gpa FROM gpa_history WHERE is_required = TRUE GROUP BY student_id, school_year HAVING AVG(gpa) >= 3.5
注意:每當在查詢中使用GROUP BY時,都只能選擇group-by列和聚合列,由於其餘列中的行級信息已被捨棄。
4
SQL 查詢執行順序
大多數人會從SELECT開始,從上到下編寫SQL查詢。
但你知道SQL引擎執行函數時要到後面才執行SELECT嗎?如下是 SQL 查詢的執行順序:
再次考慮前面的示例:
由於咱們想在計算平均GPA以前過濾掉選修課程,因此我使用WHERE is_required=TRUE代替HAVING,由於WHERE會在GROUP BY和HAVING以前執行。我不能編寫HAVING avg_gpa >= 3.5的緣由是,avg_gpa被定義爲SELECT的一部分,所以沒法在SELECT以前執行的步驟中引用它。
我建議在編寫查詢時遵循引擎的執行順序,這在編寫複雜查詢時會頗有用。
5
Window 函數
Window函數也常常出如今SQL面試中。共有五種常見的Window函數:
在SQL面試中,重要的是要瞭解排名函數之間的差別,並知道什麼時候使用LAG/LEAD。
舉例:查找每一個部門中薪水最高的前 3 名員工。
另外一個示例employee_salary表
當一個SQL問題要求計算「TOP N」時,咱們可使用ORDER BY或排名函數來回答問題。
但在這個示例中,它要求計算「每一個 Y 中的 TOP N X」,這強烈暗示咱們應該使用排名函數,由於咱們須要對每一個分區組中的行進行排名。
如下查詢剛好能找到 3 名薪水最高的員工,而不論他們的關係如何,以下:
WITH T AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY department_id ORDER BY employee_salary DESC) AS rank_in_dep FROM employee_salary) SELECT * FROM T WHERE rank_in_dep <= 3 -- Note: When using ROW_NUMBER, each row will have a unique rank number and ranks for tied records are assigned randomly. For exmaple, Rimsha and Tiah may be rank 2 or 3 in different query runs.
此外,根據關係的處理方式,咱們能夠選擇其餘排名函數。一樣,細節是很重要的!
ROW_NUMBER,RANK,DENSE_RANK結果比較
6
重複項
SQL面試中的另外一個常見陷阱是忽略數據重複。
儘管樣本數據中的某些列彷佛具備不一樣的值,但面試官仍是但願候選人考慮全部可能性,就像他們在處理真實數據集同樣。
例如:在上一個示例employee_salary表中,可讓僱員共享相同的名稱。
要避免由重複項致使的潛在問題,一種簡單方法是始終使用 ID 列惟一地標識不一樣的記錄。
舉例:使用 employee_salary 表查找每一個部門全部員工的總薪水。
正確的解決方案是 GROUP BY employee_id,而後使用 SUM(employee_salary) 計算總薪水。若是須要僱員姓名,請在末尾與 employee 表聯接以檢索僱員姓名信息。
錯誤的方法是使用 GROUP BY employee_name。
7
NULL
在SQL中,任何謂詞均可以產生三個值之一true,false和NULL,後者是unknown或missing數據值的保留關鍵字。處理NULL數據集時可能會意外地很棘手。
在SQL面試中,面試官可能會特別注意解決方案是否處理了NULL值。有時,很明顯有一列是不能nullabl的,但對於其餘大多數列來講,頗有可能會有NULL值。
建議:確認示例數據中的關鍵列是否爲nullable,若是能夠,請利用IS(NOT)NULL,IFNULL和COALESCE 之類的函數來覆蓋這些邊緣狀況。
8
交流
最後一點也很是重要:在SQL面試期間要隨時與面試官溝通交流。
我面試過的許多候選人都很沉默寡言,有疑問的時候纔會知聲。固然若是他們最終給出了完美的解決方案,那也不是什麼問題。
可是,在技術面試期間保持溝通交流每每會是有價值的。
例如:你能夠談論對問題和數據的理解,說明你計劃如何解決問題,爲何使用某些函數而不是其餘選項,以及正在考慮哪些極端狀況。
9
總結
Xinran Waibel | 做者
王強 | 譯者
https://www.infoq.cn/article/...