準備數據分析師面試時,SQL 幾乎是無法避開的一關,即使公司使用 Tableau、Power BI 或 Python進行視覺化呈現,分析師仍需要透過 SQL 從資料庫提取視覺化前需要的底層資料。
SQL 面試的重點不只是在測試語法,面試官更想透過面試,知道你是否能理解資料內容、將商業問題轉換成查詢條件、避免重複計算,並正確處理商業問題,這篇文章就來與你分享 10 道數據分析師的 SQL 基礎面試題。
練習使用的資料表
一開始,我們先假設兩張簡化的電商資料表:
一張資料表叫做customers 包含客戶資料,包括 customer_id、signup_date、country、acquisition_channel
另外一張表則為訂單紀錄表orders, 包含所有訂單紀錄,資料欄位有: order_id、customer_id、order_date、order_status、total_amount。
第 1 題:如何每個月的訂單數與營收?
這時候你是不是會想要急著開始寫你的SQL呢?
SELECT
DATE_TRUNC('month', order_date) AS order_month,
COUNT(DISTINCT order_id) AS order_count,
SUM(total_amount) AS revenue
FROM orders
GROUP BY 1
ORDER BY 1;在還沒確認商業問題之前,貿然寫出你的Query答案,可能會讓你有點扣分,解題之前,其實最重要的就是確認商業問題以及資料格式,所以先別急著寫下你的query,如果資訊只有上面提供的資料表以及資料欄位,其實並不足以讓你判斷你的Query語法應該怎麼下。
下手之前,你可以問問,例如:
1. order_date的資料格式是什麼?是日期格式嗎?還是string(字串), int(整數) 或者是timestamp格式呢?基於資料表的大小以及儲存限制,不同公司不同資料表可能會針對日期做不同的儲存格式,所以確認資料欄位的格式,絕對是第一步。
2. 每月的訂單數與營收是指完成的訂單數嗎?資料表目前的資料只包含完成的訂單嗎?如果是先完成的訂單,但後續有退貨或是換貨,該訂單的狀態會是退貨嗎?部分退貨部分取貨,那資料欄位又會怎麼顯示呢?
3. revenue是否代表實際客戶付款的金額呢?還是折扣前金額呢?如果是折扣前金額,是否需要扣除折扣金額或是運費呢?
發現了嗎?光是詢問這些問題,就可能讓你的query的處理方式完全不一樣,所以,開始回答前,請先想一下實際的商業案例可能會有哪些情況,並試想可能的情況,才會讓你的能力不僅僅停留在sql的寫手,而是專業的商業問題解析員
問完這些問題,你可能會得到:
日期的格式為整數,需要計算已完成的訂單,已完成的訂單可以以order_status = ‘completed’來判斷,先不考慮退貨,revenue是指最終營收,所以其他折扣與運費不避考慮。
SELECT
DATE_TRUNC('month', DATE_PARSE(CAST(order_date AS VARCHAR), '%Y%m%d')) AS order_month,
COUNT(DISTINCT order_id) AS order_count,
SUM(total_amount) AS revenue
FROM orders
WHERE order_status = 'completed'
GROUP BY 1
ORDER BY 1;結果是不是就跟一開始還沒釐清商業問題完全不一樣了呢?
第 2 題:如何找出消費金額最高的 10 位顧客?
看到「消費金額最高」這幾個字,你是不是已經準備把每位顧客的 total_amount 加總,再由高到低排序了呢?
SELECT
customer_id,
SUM(total_amount) AS total_spend
FROM orders
GROUP BY customer_id
ORDER BY total_spend DESC
LIMIT 10;先別急著交出這個答案。這段 SQL 在語法上可能沒有問題,但「消費金額」在商業情境中,還有很多需要確認的細節。
下手之前,你可以先問:
1. 消費金額是所有訂單的金額,還是只計算已完成的訂單?取消、付款失敗與退款訂單需要排除嗎?
2. total_amount 代表折扣前金額,還是顧客實際支付的金額?裡面是否包含運費、退款金額?
3. 資料中是否有不同幣別?如果有人使用美元消費、有人使用台幣消費,可以直接把金額放在一起比較嗎?
發現了嗎?只是要找出消費金額最高的顧客,就會牽涉訂單狀態、金額定義、幣別。技術上能夠加總,不代表這些數字在商業上真的可以直接相比。
假設面試官進一步告訴你:資料只有單一幣別、total_amount 已經是最終付款金額,而且只需要計算 order_status = ‘completed’ 的訂單,那麼 Query 就可以寫成:
SELECT
customer_id,
SUM(total_amount) AS total_spend
FROM orders
WHERE order_status = 'completed'
GROUP BY customer_id
ORDER BY total_spend DESC
LIMIT 10;這題真正想測試的,不只是你會不會使用 SUM、GROUP BY、ORDER BY 和 LIMIT,而是你是否知道「消費金額最高」背後還藏著哪些商業定義。
第 3 題:如何計算每個國家的購買顧客數?
這一題需要使用 customers 與 orders 兩張資料表。看到 customer_id 同時出現在兩張表裡,你可能會很快想到用 JOIN 把它們連起來。
SELECT
c.country,
COUNT(DISTINCT c.customer_id) AS customer_count
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.country
ORDER BY customer_count DESC;不過,在正式回答之前,還是要先確認題目裡的「國家」和「購買顧客」分別代表什麼。
你可以先問:
1. country 是會員註冊時填寫的國家、目前居住國家,還是訂單的配送國家?如果顧客購買送給住在不同居住地的收件者,應該歸在哪個國家?
2. 「購買顧客」是曾經建立訂單就算?還是至少要有一筆已完成訂單?如果是要有一筆完成訂單,是多久內完成訂單的客戶才要算?
3. 一位顧客可能有很多筆訂單,JOIN 之後會出現很多列。這時候應該計算訂單筆數,還是不重複的顧客人數?
第 3 個問題非常重要。如果直接使用 COUNT(*),一位下過 10 次訂單的顧客就會被計算 10 次,但題目問的是顧客數,因此需要使用 COUNT(DISTINCT customer_id) 避免重複計算。
假設 country 代表顧客註冊的國家,而購買顧客的定義是2025(2025-01-01~2025-12-31)至少完成過一筆訂單,那麼 SQL 可以寫成:
SELECT
c.country,
COUNT(DISTINCT c.customer_id) AS customer_count
FROM customers c
JOIN orders o ON c.customer_id = o.customer_id and
WHERE o.order_status = 'completed' and DATE(DATE_PARSE(CAST(order_date AS VARCHAR), '%Y%m%d')) between DATE('2025-01-01') AND DATE('2025-12-31')
GROUP BY c.country
ORDER BY customer_count DESC;如果題目改成「每個國家的註冊顧客數」,那就不一定需要 JOIN orders。光是「註冊顧客」與「購買顧客」兩個字的差別,就會直接改變你需要使用的資料表與篩選條件囉~
第 4 題:如何找出從未下單的會員?
這是一道很常見的 JOIN 題目。你可能知道要使用 LEFT JOIN,但真正容易出錯的地方,反而是「從未下單」到底是什麼意思。
開始寫 Query 前,可以先確認:
1. 從未下單是指完全沒有建立過任何訂單,還是沒有完成過訂單?
2. 如果會員曾經下單,但後來取消、付款失敗或全額退款,他還算是下過單嗎?
3. orders 資料表是否包含測試訂單?測試帳號與內部員工帳號是否需要排除?
假設面試官說,這裡的「從未下單」就是在 orders 資料表中完全找不到任何訂單紀錄,那麼可以使用 LEFT JOIN:
SELECT
c.customer_id,
c.signup_date,
c.country
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
WHERE o.order_id IS NULL;為什麼不能使用 INNER JOIN 呢?因為 INNER JOIN 只會保留兩張表都有出現的 customer_id,沒有訂單的會員反而會直接被排除。LEFT JOIN 則會先保留 customers 中的所有會員,再讓找不到訂單的資料呈現 NULL,因此可以用 o.order_id IS NULL 把他們找出來。
但如果題目真正想找的是「從未完成訂單的會員」,就不能只是把 order_status = ‘completed’ 寫在最後的 WHERE 條件中,否則很容易改變 LEFT JOIN 的結果。這時候,可以把完成訂單的條件放進 JOIN:
SELECT
c.customer_id,
c.signup_date,
c.country
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id AND o.order_status = 'completed'
WHERE o.order_id IS NULL;發現了嗎?「沒有下單」和「沒有完成訂單」看起來很接近,實際上卻是兩個不同的客群。面試時先說清楚你的定義,會比直接背出 LEFT JOIN 更加分。
第 5 題:如何計算不同訂單狀態的占比?
如果題目要你計算 completed、cancelled、refunded 等不同訂單狀態的占比,你可能會先想到依照 order_status 分組,再計算每一組的訂單數。
SELECT
order_status,
COUNT(*) AS order_count
FROM orders
GROUP BY order_status;但是只有各狀態的訂單數,還不能算出占比。正式往下寫之前,你可以先確認:
1. 一筆資料列就代表一張訂單嗎?還是同一張訂單會因為包含多個商品而出現多列?如果是一張訂單多列,就不能直接使用 COUNT(*)。
2. 訂單狀態是目前的最終狀態,還是每次狀態變更都會留下紀錄?如果是狀態歷程表,同一張訂單可能會被重複計算。
3. 占比的分母是所有訂單,還是只計算某段期間、特定市場或特定渠道的訂單?
4. order_status 如果是 NULL 或出現未知狀態,要獨立列出、歸類為 other,還是排除?
假設 orders 中的一列就是一張訂單、order_status 是訂單目前的最終狀態,而且分母包含資料表中的所有訂單,那麼可以搭配 Window Function 計算占比:
WITH status_count AS (
SELECT
order_status,
COUNT(*) AS order_count
FROM orders
GROUP BY order_status
),
total_count AS (
SELECT
COUNT(*) AS total_order_count
FROM orders
)
SELECT
s.order_status,
s.order_count,
ROUND(
100.0 * s.order_count / t.total_order_count,
2
) AS order_percentage
FROM status_count s
CROSS JOIN total_count t
ORDER BY s.order_count DESC;在這段 Query 中,我們先透過 status_count 計算每個 order_status 分別有多少筆訂單,再透過 total_count 計算全部訂單的總數。
最後,將每種狀態的訂單數除以全部訂單數,再乘以 100,就可以得到各訂單狀態所占的百分比。
Query 寫完後也別急著結束。你還可以檢查各狀態的百分比加總是否接近 100%,並觀察 cancelled 或 refunded 的比例是否異常。這樣回答,就不只是算出結果,也展現了你會檢查資料品質與商業合理性。
總結:SQL 面試不是只看你會不會寫語法
看完前面五道題目,你可能會發現,這些 SQL 語法其實都不算太複雜,使用的主要是 GROUP BY、JOIN、SUM、COUNT、ORDER BY。
真正困難的地方,反而是在開始寫 Query 之前,你能不能先把問題問清楚。
日期欄位是 date、timestamp、string,還是整數?營收要不要扣除退款與折扣?購買顧客是曾經建立訂單,還是至少完成過一筆訂單?從未下單,是完全沒有訂單紀錄,還是沒有成功完成的訂單?計算訂單狀態占比時,一列資料又是否真的代表一張訂單?
這些問題看起來都不是 SQL 語法,卻會直接決定你的 SQL 應該怎麼寫。如果商業定義理解錯誤,就算 Query 能夠成功執行,最後得到的答案也不一定是公司真正想知道的結果,所以啊,下次遇到 SQL 面試題時,先別急著埋頭寫答案。你可以按照下面的順序思考:
- 確認題目真正想解決的商業問題。
- 確認資料表、欄位格式與每一列資料代表的意義。
- 說明你對指標與篩選條件的假設。
- 拆解查詢步驟,再開始撰寫 SQL。
- 寫完後檢查重複資料、NULL、取消、退款與其他例外情況。
- 最後確認查詢結果在商業上是否合理。
發現了嗎?面試官想找的通常不是一位只會背語法的 SQL 寫手,而是一位能理解資料、釐清問題,並且把商業需求轉換成正確查詢邏輯的數據分析師。
這篇先和你分享前五道 SQL 基礎面試題。下一篇,我會繼續整理第 6~10 題,帶你練習日期處理、HAVING、CASE WHEN,以及更多數據分析師面試中常見的應用情境。
想繼續練習更多電商 SQL 面試題嗎?
如果你已經完成上面的題目,接下來可以試著挑戰更多貼近實際工作情境的 SQL 題目。
我整理了一份《電商產業 SQL 面試實戰題庫》,收錄 24 道電商商業案例,涵蓋付款失敗率、取消與退款、實際營收、新舊客、回購率、商品表現、MoM、QoQ、優惠券成效與購物轉換漏斗。
每一道題目都會提供資料表與欄位,讓你先練習釐清商業問題、拆解查詢步驟,再對照 Athena SQL 與 MySQL 8.0 的參考答案,這裏購買:https://buymeacoffee.com/aderlabsharon/e/572913
最後也提供讀者專屬折扣碼:BLOG,結帳時輸入折扣碼即可享有9折優惠~
Buy me a coffee 用行動支持我的內容創作
如果我的文章對你有幫助,歡迎用小額贊助支持內容創作,也歡迎留言分享你的 SQL 面試經驗。



