本日主題:用 30 題把這週所學整合練熟 + 面試常見 SQL 題 預計時間:2.5 小時(動手日) 對應主教材:第 6.1 節
一、今日學習目標
- [ ] 看到題目能直接寫出 SQL
- [ ] 整合 WHERE / 排序 / 聚合 / 分組 / JOIN / 子查詢
- [ ] 練習面試常見 SQL 題型
用第 1 天建立的
employees與departments表來練。建議先自己寫,再看解答。
二、30 題題庫(附完整解答)
基礎查詢(1~8)
第 1 題:查出所有員工的姓名與薪水。
SELECT name, salary FROM employees;
| name | salary |
|---|---|
| 王小明 | 52000 |
| 李大華 | 48000 |
| 陳美麗 | 45000 |
| 林志強 | 60000 |
| 張雅婷 | 55000 |
| 黃建宏 | 47000 |
第 2 題:查出 IT 部門的所有員工。
SELECT * FROM employees WHERE department = 'IT';
注意:字串要加單引號,且大小寫要與資料一致。
第 3 題:查薪水大於 50000 的員工。
SELECT name, salary FROM employees WHERE salary > 50000;
結果:王小明(52000)、林志強(60000)、張雅婷(55000)。
第 4 題:查薪水介於 45000~55000 的員工。
SELECT name, salary FROM employees
WHERE salary BETWEEN 45000 AND 55000;
BETWEEN 包含兩端(45000 和 55000 都包含)。 也可以寫成:
WHERE salary >= 45000 AND salary <= 55000
第 5 題:查姓「王」的員工。
SELECT * FROM employees WHERE name LIKE '王%';
%代表任意長度字元。'王%'表示以「王」開頭。
第 6 題:查 IT 或維修部門的員工。
-- 方法 1:用 IN
SELECT * FROM employees WHERE department IN ('IT','維修');
-- 方法 2:用 OR
SELECT * FROM employees
WHERE department = 'IT' OR department = '維修';
IN 寫法更簡潔,多個值時推薦用 IN。
第 7 題:查所有員工,依薪水由高到低排序。
SELECT * FROM employees ORDER BY salary DESC;
DESC = 降冪(大到小),ASC = 升冪(小到大,預設)。
第 8 題:查薪水最高的前 3 名。
SELECT name, salary FROM employees
ORDER BY salary DESC
LIMIT 3;
結果:林志強(60000)、張雅婷(55000)、王小明(52000)。
SQL Server 語法:
SELECT TOP 3 name, salary FROM employees ORDER BY salary DESC
聚合與分組(9~18)
第 9 題:算出全公司員工人數。
SELECT COUNT(*) AS 員工人數 FROM employees;
結果:6。
第 10 題:算出全公司平均薪水。
SELECT AVG(salary) AS 平均薪水 FROM employees;
結果:51166(取整數)。
第 11 題:算出最高薪與最低薪。
SELECT MAX(salary) AS 最高薪, MIN(salary) AS 最低薪 FROM employees;
結果:最高 60000、最低 45000。
第 12 題:算出薪水總和。
SELECT SUM(salary) AS 薪水總和 FROM employees;
結果:307000。
第 13 題:每個部門各有幾人。
SELECT department, COUNT(*) AS 人數
FROM employees
GROUP BY department;
| department | 人數 |
|---|---|
| IT | 3 |
| 會計 | 1 |
| 維修 | 2 |
第 14 題:每個部門的平均薪水。
SELECT department, AVG(salary) AS 平均薪水
FROM employees
GROUP BY department;
| department | 平均薪水 |
|---|---|
| IT | 51666 |
| 會計 | 45000 |
| 維修 | 53500 |
第 15 題:每個部門的最高薪。
SELECT department, MAX(salary) AS 最高薪
FROM employees
GROUP BY department;
| department | 最高薪 |
|---|---|
| IT | 55000 |
| 會計 | 45000 |
| 維修 | 60000 |
第 16 題:找出平均薪水大於 48000 的部門。
SELECT department, AVG(salary) AS 平均薪水
FROM employees
GROUP BY department
HAVING AVG(salary) > 48000;
結果:IT(51666)、維修(53500)。
關鍵:對聚合結果篩選要用 HAVING,不能用 WHERE。
第 17 題:找出人數超過 1 人的部門。
SELECT department, COUNT(*) AS 人數
FROM employees
GROUP BY department
HAVING COUNT(*) > 1;
結果:IT(3)、維修(2)。
第 18 題:2024 年(含)以後到職的員工人數。
SELECT COUNT(*) AS 人數
FROM employees
WHERE hire_date >= '2024-01-01';
結果:3(王小明 2024-03-01、張雅婷 2025-02-01、黃建宏 2024-11-11)。
日期比較用字串格式 'YYYY-MM-DD',SQLite 中以文字排序即可正確比較。
JOIN(19~24)
第 19 題:查每位員工姓名 + 部門名稱(用 dept_id 關聯)。
SELECT e.name, d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.id;
| name | dept_name |
|---|---|
| 王小明 | IT |
| 李大華 | IT |
| 陳美麗 | 會計 |
| 林志強 | 維修 |
| 張雅婷 | IT |
| 黃建宏 | 維修 |
第 20 題:用 LEFT JOIN 列出所有部門,即使沒人也要顯示。
SELECT d.dept_name, e.name
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.id;
如果某部門沒有員工,e.name 會顯示 NULL。 注意:departments 要放在左邊(FROM departments)。
第 21 題:每個部門名稱 + 人數。
SELECT d.dept_name, COUNT(e.id) AS 人數
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.id
GROUP BY d.dept_name;
用 LEFT JOIN 確保沒人的部門也會顯示(人數為 0)。 用 COUNT(e.id) 而非 COUNT(*),因為 NULL 不計入。
第 22 題:每個部門名稱 + 平均薪水。
SELECT d.dept_name, AVG(e.salary) AS 平均薪水
FROM departments d
JOIN employees e ON e.dept_id = d.id
GROUP BY d.dept_name;
第 23 題:查 IT 部門(用部門表關聯)所有人的姓名。
SELECT e.name
FROM employees e
JOIN departments d ON e.dept_id = d.id
WHERE d.dept_name = 'IT';
透過 JOIN 用 departments 表的名稱來篩選,而非直接用 employees.department。
第 24 題:找出沒有任何員工的部門。
SELECT d.dept_name
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.id
WHERE e.id IS NULL;
解題思路: 1. LEFT JOIN 保留所有部門 2. 沒有員工的部門,e.id 會是 NULL 3. 用 WHERE e.id IS NULL 篩出來
以目前的測試資料,三個部門都有員工,結果為空。可以先新增一個無人部門測試:
INSERT INTO departments VALUES (4,'人資');
異動(25~30)
第 25 題:新增一名員工。
INSERT INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (7, '吳俊傑', 'IT', 1, 50000, '2025-05-01');
建議指定欄位名稱,不要用
INSERT INTO employees VALUES (...)。
第 26 題:把某員工薪水調為 60000。
-- Step 1: 先確認目標
SELECT * FROM employees WHERE id = 7;
-- Step 2: 更新
UPDATE employees SET salary = 60000 WHERE id = 7;
-- Step 3: 驗證
SELECT * FROM employees WHERE id = 7;
三步驟:確認 → 更新 → 驗證。
第 27 題:把 IT 部門所有人加薪 2000。
-- 先看目前 IT 部門薪水
SELECT name, salary FROM employees WHERE department = 'IT';
-- 加薪
UPDATE employees SET salary = salary + 2000
WHERE department = 'IT';
-- 驗證
SELECT name, salary FROM employees WHERE department = 'IT';
用
salary = salary + 2000做相對調整,而非設定絕對值。
第 28 題:刪除某一名員工(先 SELECT 確認)。
-- Step 1: 確認要刪的對象
SELECT * FROM employees WHERE id = 7;
-- Step 2: 確認只有 1 筆後刪除
DELETE FROM employees WHERE id = 7;
-- Step 3: 驗證已刪除
SELECT * FROM employees WHERE id = 7; -- 應無結果
永遠先 SELECT 確認,再 DELETE。
第 29 題:把某員工的部門改成「維修」。
-- 要同時改 department 和 dept_id,保持資料一致
UPDATE employees
SET department = '維修', dept_id = 3
WHERE id = 2;
-- 驗證
SELECT * FROM employees WHERE id = 2;
注意:如果表有 department 文字欄位和 dept_id 數字欄位,兩個都要改。
第 30 題:統計調整後每個部門的平均薪水(驗證第 27 題的結果)。
SELECT department, COUNT(*) AS 人數, AVG(salary) AS 平均薪水
FROM employees
GROUP BY department;
驗證 IT 部門的平均薪水是否比原本多了約 2000。
三、面試常見 SQL 加分題(額外 10 題)
第 31 題:查出每個部門薪水最高的員工。
-- 方法:子查詢
SELECT e.name, e.department, e.salary
FROM employees e
WHERE e.salary = (
SELECT MAX(salary) FROM employees
WHERE department = e.department
);
這是「相關子查詢」(Correlated Subquery),內層查詢引用外層的 e.department。
第 32 題:查出薪水排名第 2 高的員工。
-- 方法 1:用 LIMIT + OFFSET
SELECT name, salary FROM employees
ORDER BY salary DESC
LIMIT 1 OFFSET 1;
-- 方法 2:子查詢排除最高薪
SELECT name, salary FROM employees
WHERE salary = (
SELECT MAX(salary) FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees)
);
第 33 題:用 CASE WHEN 將員工分為高薪/中薪/一般,並統計各級人數。
SELECT
CASE
WHEN salary >= 55000 THEN '高薪'
WHEN salary >= 48000 THEN '中薪'
ELSE '一般'
END AS 薪資等級,
COUNT(*) AS 人數
FROM employees
GROUP BY
CASE
WHEN salary >= 55000 THEN '高薪'
WHEN salary >= 48000 THEN '中薪'
ELSE '一般'
END;
第 34 題:查出到職日期最早的員工。
SELECT name, hire_date FROM employees
WHERE hire_date = (SELECT MIN(hire_date) FROM employees);
結果:林志強(2021-09-20)。
第 35 題:查出每個部門到職最久的員工。
SELECT e.name, e.department, e.hire_date
FROM employees e
WHERE e.hire_date = (
SELECT MIN(hire_date) FROM employees
WHERE department = e.department
);
第 36 題:建立一個 VIEW 顯示員工詳細資訊。
CREATE VIEW v_employee_detail AS
SELECT e.id, e.name, e.salary, e.hire_date,
d.dept_name
FROM employees e
JOIN departments d ON e.dept_id = d.id;
-- 使用 VIEW
SELECT * FROM v_employee_detail WHERE dept_name = 'IT';
第 37 題:查出薪水高於其部門平均的員工。
SELECT e.name, e.department, e.salary
FROM employees e
WHERE e.salary > (
SELECT AVG(salary) FROM employees
WHERE department = e.department
);
面試熱門題!使用「相關子查詢」比較個人薪水與其部門平均。
第 38 題:查出所有部門的薪水統計(人數、平均、最高、最低、總和)。
SELECT d.dept_name,
COUNT(e.id) AS 人數,
AVG(e.salary) AS 平均,
MAX(e.salary) AS 最高,
MIN(e.salary) AS 最低,
SUM(e.salary) AS 總和
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.id
GROUP BY d.dept_name;
第 39 題:查出 2023 年到 2024 年之間到職的員工,並依部門分組統計人數。
SELECT department, COUNT(*) AS 人數
FROM employees
WHERE hire_date BETWEEN '2023-01-01' AND '2024-12-31'
GROUP BY department;
第 40 題:為 employees 表的 department 欄位建立索引,並解釋為什麼。
CREATE INDEX idx_emp_department ON employees(department);
解釋:department 經常用在 WHERE 篩選和 GROUP BY 分組中,建立索引可以加速這些查詢。尤其在資料量大時(如上萬筆)效果顯著。
四、常見誤解
| 誤解 | 正確觀念 |
|---|---|
| 「30 題做完就夠了」 | 要能「不看答案寫出來」才算真的會,多練幾次 |
| 「面試只考 SELECT」 | UPDATE/DELETE 和安全習慣也常被問 |
| 「子查詢太難不會考」 | 基本的子查詢(如找最高薪、高於平均)是常見面試題 |
| 「寫出來就好」 | 面試時要能「邊寫邊講」解題思路,展現邏輯能力 |
五、面試加分小知識
- 面試手寫 SQL 技巧:先寫 FROM(確定資料來源),再寫 WHERE(篩選條件),最後寫 SELECT(要顯示什麼)。
- NULL 陷阱:COUNT(*) 包含 NULL,COUNT(欄位) 排除 NULL,面試常考。
- 執行順序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY,理解這個順序就不會搞混。
- 相關子查詢 vs 非相關子查詢:非相關子查詢只執行一次,相關子查詢每列都執行一次(效能差但有時必要)。
六、今日實作任務(產出)
- [ ] 完成 30 題(基礎),記錄你的 SQL 與結果
- [ ] 挑戰面試加分題(31~40)
- [ ] 標記寫不出來的題目,明天複習加強
七、延伸閱讀
- LeetCode SQL 題庫 — 線上 SQL 練習平台
- HackerRank SQL — 另一個 SQL 練習平台
- SQL 面試 50 題 — 經典 SQL 面試題集
八、今日檢核
- [ ] 我完成了 30 題基礎題
- [ ] 我能獨立寫出分組與 JOIN 的查詢
- [ ] 我練習了面試加分題
- [ ] 我知道自己還要加強哪幾題
⬅️ 上一天:Day 5 | 🏠 本週總覽 | ➡️ 下一天:Day 7 — 複習與手寫測驗