[面試分享 ] SQL 面試準備攻略:準備技巧、刷題資源與範例解析

更新於 發佈於 閱讀時間約 25 分鐘
本文基於作者 20+ 場新創及全球科技公司的面試經驗,以及擔任面試官的實戰經驗,深度解析 SQL 技術面試的評估標準與準備策略,並提供 5 道經典題目解析,助你順利通過技術關卡!

SQL 面試會考些什麼?

(1) 基礎 SQL 能力

(1) 正確且具備邏輯的把 SQL 寫出來 (2) 能善用 where 或其他方法有效優化 SQL (3) 易讀性的 Format 以及註解

範例題目

raw-image

評分標準

  • 正確且具備邏輯的把 SQL 寫出來
    • 先求有再求好!我作為面試官的經驗來說,Junior 的 SQL 面試有 85% 在測驗語法。產品經驗可以入職後累積,但如果連基礎能力都沒有,主管還需要花時間指導 SQL,這類候選人高機率會被刷掉。
    • 當題目變得複雜無法用一段 query 寫完的時候,請善用 CTE 或是 Subquery 進行拆解。我個人是 CTE 派因為閱讀性較高,面試官可以很好的從頭到尾理解資料處理的邏輯。
    • 另外,我會盡量以設計 pipeline 的角度,而不是一次性 ad-hoc query 去作答。這樣的好處是以後遇到不同的需求或是題目,你都可以用同一套邏輯去解決。
      -- Ad-hoc 版本
      WITH may AS (
      SELECT user_id
      FROM orders
      WHERE DATE_TRUNC(date, MONTH) = "2025-05-01"
      ),
      june AS (
      SELECT user_id
      FROM orders
      WHERE DATE_TRUNC(date, MONTH) = "2025-06-01"
      )
      SELECT
      COUNT(DISTINCT june.user_id) / COUNT(DISTINCT may.user_id) AS retention_rate
      FROM may
      LEFT JOIN june
      ON may.user_id = june.user_id
      	-- pipeline 設計理念版本
      WITH retention AS (
      SELECT
      DATE_TRUNC(o1.date, MONTH) AS purchase_month,
      COUNT(DISTINCT o1.user_id) AS users
      COUNT(DISTINCT o2.user_id) AS reorder_users
      FROM orders AS o1
      LEFT JOIN orders AS o2
      ON o1.user_id = o2.user_id
      AND DATE_TRUNC(o1.date, MONTH) = DATE_SUB(DATE_TRUNC(o2.date, MONTH), INTERVAL 1 MONTH)
      WHERE DATE_TRUNC(o1.date, MONTH) = "2025-05-01"
      )
      SELECT
      purchase_month,
      reorder_users / users AS retention_rate
      FROM retention
      -- WHERE purchase_month = "2025-05-01"
  • 能善用 where 或其他方法有效優化 SQL
    • 我個人認為優化是最常被忽略的一環,即便在日常作業中,很多人也不太在意優化,最後可能導致 pipeline timeout 以及浪費運算資源產生的超額帳單。
    • 最直觀的優化就是減少不必要的資料獲取。範例題當中,我們已經知道兩個條件 (1) 日期 (2) 訂閱用戶,我們可以對兩張 table 都進行資料篩選,減少 join 所需要的資料量。
  • 易讀性的 Format 以及註解
    • 註解的部分看你是線上考或是機考,線上考我會先闡述想法後再開始作答,比較少有註解。機考則是儘量都有註解,特別是需要多個 CTE 的題目,我會把每個 CTE 的目的寫清楚,方便面試官改考卷。
    • Format 部分很看面試官個人偏好,但我個人非常注重。你可以有自己風格,但請貫徹到底。不要看這個好像很小、很沒意義,未來會大大影響到 PR review 以及 debug 的速度。
  • -- 無格式化版本
    SELECT date,
    platform,count(distinct user_id) users
    FROM table
    WHERE (platform = "android"
    and date = "2025-05-01")or (
    platform = "ios" AND (
    date = "2025-05-03" and is_subscribed))or(
    platform = "web"
    and date = "2025-05-02")
    group by date,
    platform
    order by date
    ASC
    -- 格式化版本
    SELECT
    date,
    platform,
    COUNT(DISTINCT user_id) AS users
    FROM table
    WHERE
    (
    platform = "android"
    AND date = "2025-05-01"
    ) OR (
    platform = "ios"
    AND (
    date = "2025-05-03"
    AND is_subscribed
    )
    ) OR (
    platform = "web"
    AND date = "2025-05-02"
    )
    GROUP BY date, platform
    ORDER BY date

如何準備 - 刷題

為什麼需要刷題?

  • 即便你是身經百戰的分析師,我還是強烈建議要刷題,量可以少但不能沒有。刷題的用意是模擬面試環境,並提前熟悉各種不同的題型,一旦面試出現跟你日常工作毫無相關的資料或是陌生的指標,很容易就慌了手腳。
  • 以上述範例來說,日常工作中我們會 GROUP BY 日期做計算,然後把結果丟進 Excel 或是 BI tool 製圖,這樣做會導致你拿不到 2025/05/02 的資料,但多半不影響視覺化的結果。如果你沒有事先碰過這類題目,面試當下你可能就愣住了,不曉得怎麼在結果中列出所有日期的資料。
  • 另外,刷題的過程中可以接觸到不同產業以及公司的考古題,而 SQL 考試中的問題,同時也就是指標,很有可能會跟應徵職位的日常工作息息相關,等於同時也準備後續的 Product 技術關。

去哪刷?怎麼刷?

  • 我以前刷題都在 LeetCode 進行,但我覺得題目品質不太好,過於簡單,和真實考題的難度脫鉤,再加上有些題目很刻意在考語法。後來轉戰使用Stratascratch 覺得還不錯,上面可以篩選公司找考古題,除了 SQL 以外也有統計和 product case 等相關的問題可以練習。文章最後也會放一些題目解析。
  • 我自己是會把 Hard 刷完一輪,如果還有時間才會刷 Medium 維持手感,Easy 過於簡單我完全不碰。頻率的部分,我大概每天刷 1 - 3 題,取決於多快可以把 Hard 刷乾。
  • 除了正確解答以外,刷題的速度也重要。在準備 Meta 面試的時候,我是會限定自己要在 10 分鐘以內寫完 Hard,然後完成優化,藉此模擬面試當下的壓力測試。

(2) Product Mindset

當面對不熟悉的產品以及數據下,在有限的時間內有條有理的闡述自己的想法,最終透過 SQL 實現,就是這類型題目的核心

範例題目

raw-image

評分標準

  • 這類題目多半出現在 Senior 的面試中,更多的是了解你對於產品的理解程度,以及在面對不熟悉的產品時如何拆解問題,並來回與面試官溝通。

如何準備

  • 以上述範例來說,你會需要定義何謂 Top,DAU、總時長或是總使用次數都可以是指標。此時,你要先提出假設並根據假設進行解答。舉例來說:
    • 不同類別的 app 有不同的 Top 定義,假設這類 app 都是社群媒體相關的,我們應該以 DAU 作為主要指標,因為 social media 最主要的目標是不斷地吸引用戶持續使用。
    • 然而,如果是遊戲類型的居多,duration 可能就會變得更為重要。
  • 我個人覺得這部分不用在 SQL 階段特別準備。我會這樣說是因為在準備 product case 的時候同時就已經在思考這些問題了。舉例來說:「我們發現流量在某天爆增然後隔天又暴跌,你會怎麼解讀該數據?」,這類題目中已經包含處理資料以及解析數據的能力。

常見 SQL Function

General Function

  • 最基本的語法: select, from, where
  • Aggregate Function: sum, count, count distinct, avg, …
  • union 與 union all 的差異: 前者去重複,後者不會

Window Function

  • Ranking (rank, dense_rank, row_number)
raw-image
  • lag vs lead
  • precentile (這個我很少遇到,而且不是每個類型的 SQL 都通用)
raw-image

Date Function

raw-image

SQL 刷題解析

[Medium] Election Results

重點

  • 三種可能
    • 投廢票 (空白字串)
    • 投一個候選人
    • 投多個候選人
  • 每個人的 votes 只看到小數點第三位
  • 有可能有多個第一名

解題邏輯

  • 計算每個 voter 總共投了幾個候選人,並且均分票數
  • 加總後排序,並取得第一名

答案

WITH voter_data AS (
SELECT
voter,
1.0 / COUNT(DISTINCT candidate) AS votes
FROM voting_results
WHERE candidate IS NOT NULL AND candidate != ''
GROUP BY voter
),
final_result AS (
SELECT
vr.candidate,
SUM(ROUND(votes, 3)) AS votes -- 這裡最好問清楚 ROUND 是針對最後票數,還是針對每個人
FROM voting_results AS vr
INNER JOIN voter_data AS vd
ON vr.voter = vd.voter
WHERE vr.candidate IS NOT NULL AND vr.candidate != ''
GROUP BY vr.candidate
),
ranking AS (
SELECT
*,
RANK() OVER(ORDER BY votes DESC) AS final_rank
FROM final_result
)
SELECT candidate
FROM ranking
WHERE final_rank = 1

[Medium] Premium Accounts

重點

  • 只需要最早的七個日期答案 → Limit 7 or row_number() ≤ 7
  • actively paying 的定義是 final_price 不等於 0
  • reactively paying 的定義只看七天後,不管中間

解題邏輯

  • 針對 account id 和 date 進行 self join
  • 分別計算有多少 actively paying 和 reactively paying
  • sort 日期後取前七筆資料

答案

SELECT
p1.entry_date,
COUNT(DISTINCT CASE WHEN p1.final_price != 0 THEN p1.account_id END) AS premium_paid_accounts,
COUNT(DISTINCT CASE WHEN p1.final_price != 0 AND p2.final_price != 0 THEN p1.account_id END) AS premium_paid_accounts_after_7d
FROM premium_accounts_by_day AS p1
LEFT JOIN premium_accounts_by_day AS p2
ON p1.account_id = p2.account_id
AND DATEDIFF(p2.entry_date, p1.entry_date) = 7
GROUP BY p1.entry_date
ORDER BY p1.entry_date
LIMIT 7

[Hard] Marketing Campaign Success [Advanced]

重點

  • Campaign 影響定義
    • Campaign 只會在首購日後開始作用 → 首購日
    • 購買首購日相同商品將不會被歸因 → 首購日中的所有商品
  • 題目沒有特別標明 Campaign 是否持續進行,以及其歸因範圍,如果面試中有遇到類似問題,建議和面試官確認邏輯。 ex: campaign 只會持續七天

解題邏輯

  • 取得首購日以及首購日中所有商品
    • 我是把兩個邏輯切開來計算,先拿到首購日,進行 join 取得首購商品
    • 精簡優化的話,可以在第一個 CTE 用 window function 計算首購日後,最終 join 的時候篩選首購日中的商品
  • 確認首購日後購買的商品是否不同,當至少一個商品不同時,歸因給 campaign

答案

-- First Purchase Date
-- First Purchase Item ID

-- first purchase date products
WITH fdo AS (
SELECT
user_id,
product_id,
DATE(created_at) AS purchase_date,
FIRST_VALUE(DATE(created_at)) OVER (PARTITION BY user_id ORDER BY created_at) AS first_purchase_date
FROM marketing_campaign
),
retention AS (
SELECT
mc.user_id,
mc.product_id,
MAX(CASE WHEN mc.product_id = fdo.product_id THEN 1 ELSE 0 END) AS has_purchased
FROM marketing_campaign AS mc
INNER JOIN (
SELECT
user_id,
product_id,
first_purchase_date
FROM fdo
WHERE purchase_date = first_purchase_date
) AS fdo
ON mc.user_id = fdo.user_id
AND DATE(mc.created_at) > fdo.first_purchase_date #DATE_ADD(ftb.first_purchase_date, INTERVAL 1 DAY)
GROUP BY mc.user_id, mc.product_id
)
SELECT COUNT(DISTINCT user_id) AS users
FROM retention
WHERE has_purchased = 0

[Hard] Retention Rate

重點

  • account_id 為單位計算 retention rate
  • retention rate 的定義是該月後有回訪即算,不論多晚回訪
  • 要計算 Jan 2021 retention rate / Dec 2020 retention rate,例外處理為 0

解題邏輯

  • 討論區有解答是直接計算資料庫中每個 account 最後的互動月份,再以此計算 retention rate,雖然這樣也沒錯,但如果今天把 retention 的定義改為僅考慮下一個月,這種做法就不可行。因此,我會用設計 pipeline 的寫法,而不是針對題目客製的答案。
  • self join 去取得該月後所有的資料
    • 如果需要更改 retention 的定義,在第一個 join 的 condition 做調整即可
  • 分別計算 2020 Dec 和 2021 Jan 的 retention rate
  • 相除後做例外處理取得最終答案

答案

WITH retention_raw AS (
SELECT
DATE_FORMAT(e1.record_date, '%Y-%m') AS record_month,
e1.user_id,
e1.account_id,
MAX(CASE WHEN e2.record_date IS NOT NULL THEN 1 ELSE 0 END) AS has_retention
FROM sf_events AS e1
LEFT JOIN sf_events AS e2
ON DATE_FORMAT(e1.record_date, '%Y-%m') < DATE_FORMAT(e2.record_date, '%Y-%m')
AND e1.user_id = e2.user_id
AND e1.account_id = e2.account_id
GROUP BY DATE_FORMAT(e1.record_date, '%Y-%m'), e1.user_id, e1.account_id
),
dec_retention AS (
SELECT
account_id,
COUNT(DISTINCT CASE WHEN has_retention = 1 THEN user_id END) / COUNT(DISTINCT user_id) AS retention_rate
FROM retention_raw
WHERE record_month = "2020-12"
GROUP BY account_id
),
jan_retention AS (
SELECT
account_id,
COUNT(DISTINCT CASE WHEN has_retention = 1 THEN user_id END) / COUNT(DISTINCT user_id) AS retention_rate
FROM retention_raw
WHERE record_month = "2021-01"
GROUP BY account_id
)
SELECT
j.account_id,
IFNULL(j.retention_rate / d.retention_rate, 0) AS retention
FROM jan_retention AS j
LEFT JOIN dec_retention AS d
ON d.account_id = j.account_id

[Hard] Most Popular Client For Calls

重點

  • most popular client,有可能會有多個值,最好和考官確認期待 output
  • popular 的定義是 number of users
  • users 需要進行篩選,他們產生的 event 資料中要有至少 50% 是 call 相關的 event

解題邏輯

  • 根據條件篩選合格 user
  • group by client 計算合格 user 數量
  • 依照 user 數量排序,取得最熱門的 client
    • 如果僅需一個結果,可以用 row_number,不過要再三確認其排序邏輯
    • 如果有多個同樣熱門的 client 且需要把所有結果都列出來,用 rank 或 dense_rank 才會是正確答案

答案

-- most popular client_id, 1 or multiple output?
-- video events >= 50% of total events

WITH events_agg AS (
SELECT
client_id,
user_id,
1.0 * COUNT(DISTINCT
CASE
WHEN event_type IN (
'video call received',
'video call sent',
'voice call received',
'voice call sent'
) THEN id
END
) / COUNT(DISTINCT id) AS call_events_share
FROM fact_events
GROUP BY client_id, user_id
),
client_user_cnt AS (
SELECT
client_id,
COUNT(DISTINCT user_id) AS users
FROM events_agg
WHERE call_events_share >= 0.5
),
client_sort AS (
SELECT
client_id,
RANK() OVER(PARTITION BY client_id ORDER BY users DESC) AS client_rank
FROM client_user_cnt
)
SELECT client_id
FROM client_sort
WHERE client_rank = 1
留言
avatar-img
留言分享你的想法!
avatar-img
分析遊蹤
11會員
51內容數
多元化的文章內容,主題包括數據分析分享、旅遊心得和個人投資心得。我們提供有價值的內容,幫助讀者探索數據世界、計劃下一次旅行和做出明智的財務決策。
分析遊蹤的其他內容
2024/08/03
Tiktok 面試內容因面試官而異。遇到的面試官問題都很 hard core,針對技術問題有非常細部的討論。建議想面試 Tiktok 的人給自己多點時間面試,除了深以外也要顧及廣度
Thumbnail
2024/08/03
Tiktok 面試內容因面試官而異。遇到的面試官問題都很 hard core,針對技術問題有非常細部的討論。建議想面試 Tiktok 的人給自己多點時間面試,除了深以外也要顧及廣度
Thumbnail
2024/06/18
Dcard 是我在 2021 年所有面試公司中體驗最糟糕的,面試官基本上就是有幾年經驗的分析師,技術水平也不是非常卓越,對答中面試官始終採取上對下的高姿態,一臉傲氣且不耐煩地回應你對於問題的疑惑。後續和其他友人閒聊才知道,大家都對於 Dcard 的面試嗤之以鼻。
Thumbnail
2024/06/18
Dcard 是我在 2021 年所有面試公司中體驗最糟糕的,面試官基本上就是有幾年經驗的分析師,技術水平也不是非常卓越,對答中面試官始終採取上對下的高姿態,一臉傲氣且不耐煩地回應你對於問題的疑惑。後續和其他友人閒聊才知道,大家都對於 Dcard 的面試嗤之以鼻。
Thumbnail
2024/06/15
Appier 面試體驗滿好的,對談過程中很順暢且快速,大約兩週多就結束所有面試進入最後薪資談判。值得注意的是該崗位並沒有標示出職等,面試官會根據面試內容去給予其職等,能力達標會直接掛 Senior level。薪資方面應該是台灣數據分析產業數一數二高的,有興趣的人可以試試
Thumbnail
2024/06/15
Appier 面試體驗滿好的,對談過程中很順暢且快速,大約兩週多就結束所有面試進入最後薪資談判。值得注意的是該崗位並沒有標示出職等,面試官會根據面試內容去給予其職等,能力達標會直接掛 Senior level。薪資方面應該是台灣數據分析產業數一數二高的,有興趣的人可以試試
Thumbnail
看更多
你可能也想看
Thumbnail
網路上琳琅滿目的面試準備技巧,其中不乏許多常見的表達架構,但是在面試的現場,臨陣磨槍的背誦架構,幫助大嗎? 面試的本質在於雙方了解、面試官的職責在於判斷你與公司以及職務的合適程度,因此在保持禮貌和尊重的前提下,對於自身現況盡量坦誠以告、真實反應吧!
Thumbnail
網路上琳琅滿目的面試準備技巧,其中不乏許多常見的表達架構,但是在面試的現場,臨陣磨槍的背誦架構,幫助大嗎? 面試的本質在於雙方了解、面試官的職責在於判斷你與公司以及職務的合適程度,因此在保持禮貌和尊重的前提下,對於自身現況盡量坦誠以告、真實反應吧!
Thumbnail
這篇文章分享了面試中常詢問的後續流程和時間相關問題,包括詢問後續面試關卡和流程、預計通知下一關面試時間等問題。建議在面試中詢問這些問題,以便掌握招募後續流程和時間,並展現對職缺的熱忱。
Thumbnail
這篇文章分享了面試中常詢問的後續流程和時間相關問題,包括詢問後續面試關卡和流程、預計通知下一關面試時間等問題。建議在面試中詢問這些問題,以便掌握招募後續流程和時間,並展現對職缺的熱忱。
Thumbnail
這篇文章分享了作者對銀行考試的準備和麵試的心得,包含了考試和面試的準備建議以及根據不同銀行的個人想法。如果你正準備銀行考試,這篇文章會給你一些有用的思路。
Thumbnail
這篇文章分享了作者對銀行考試的準備和麵試的心得,包含了考試和面試的準備建議以及根據不同銀行的個人想法。如果你正準備銀行考試,這篇文章會給你一些有用的思路。
Thumbnail
畢業季來臨,對於社會新鮮人來說,面試是展現自己專業能力和個人魅力的重要機會。小編為大家整理了一些在英文面試中常用的句型和....
Thumbnail
畢業季來臨,對於社會新鮮人來說,面試是展現自己專業能力和個人魅力的重要機會。小編為大家整理了一些在英文面試中常用的句型和....
Thumbnail
Professional Cloud Database Engineer 考試/資源/心得整理 |Google Cloud
Thumbnail
Professional Cloud Database Engineer 考試/資源/心得整理 |Google Cloud
Thumbnail
🐳本文收錄於 1111人力銀行 面試經驗談;每週五分鐘,掌握實務技巧,讓你從容應對職場事務!
Thumbnail
🐳本文收錄於 1111人力銀行 面試經驗談;每週五分鐘,掌握實務技巧,讓你從容應對職場事務!
Thumbnail
整理高中考大學各學群常見面試問題,學生可做為參考練習
Thumbnail
整理高中考大學各學群常見面試問題,學生可做為參考練習
Thumbnail
求職一定會遇到的一個關卡,就是「面試」。對於新鮮人或很長時間沒有經歷面試的求職者來說,常常聽到「面試」就覺得皮皮挫!但其實只要做好充足準備,事先掌握面試的流程和內容,就像是考試前就得到了考題一樣,只要好好準備,一定就能獲得期望的成果!
Thumbnail
求職一定會遇到的一個關卡,就是「面試」。對於新鮮人或很長時間沒有經歷面試的求職者來說,常常聽到「面試」就覺得皮皮挫!但其實只要做好充足準備,事先掌握面試的流程和內容,就像是考試前就得到了考題一樣,只要好好準備,一定就能獲得期望的成果!
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News