本日主題:不靠工具,手寫 SQL(模擬面試白板題) 預計時間:1.5 小時 對應主教材:第 6.1 節


一、今日學習目標

  • [ ] 複習 SQL 執行順序
  • [ ] 不看資料手寫 SQL
  • [ ] 準備面試 SQL 口述/白板題
  • [ ] 複習本週所有觀念(含子查詢、VIEW、INDEX)

二、本週重點總複習

2.1 SQL 執行順序(理解這個就不會亂)

┌────────────────────────────────────────────────────────┐
│                SQL 執行順序                              │
├────────────────────────────────────────────────────────┤
│                                                          │
│  書寫順序:SELECT → FROM → WHERE → GROUP BY → HAVING     │
│           → ORDER BY → LIMIT                             │
│                                                          │
│  執行順序:FROM → WHERE → GROUP BY → HAVING → SELECT     │
│           → ORDER BY → LIMIT                             │
│                                                          │
│  ┌─────┐                                                │
│  │FROM │ ① 決定資料來源(哪張表)                         │
│  └──┬──┘                                                │
│     ↓                                                    │
│  ┌─────┐                                                │
│  │WHERE│ ② 篩選個別列                                   │
│  └──┬──┘                                                │
│     ↓                                                    │
│  ┌────────┐                                             │
│  │GROUP BY│ ③ 分組                                      │
│  └──┬─────┘                                             │
│     ↓                                                    │
│  ┌──────┐                                               │
│  │HAVING│ ④ 篩選分組結果                                 │
│  └──┬───┘                                               │
│     ↓                                                    │
│  ┌──────┐                                               │
│  │SELECT│ ⑤ 選擇要顯示的欄位                             │
│  └──┬───┘                                               │
│     ↓                                                    │
│  ┌────────┐                                             │
│  │ORDER BY│ ⑥ 排序結果                                   │
│  └──┬─────┘                                             │
│     ↓                                                    │
│  ┌─────┐                                                │
│  │LIMIT│ ⑦ 取前 N 筆                                    │
│  └─────┘                                                │
└────────────────────────────────────────────────────────┘

2.2 重點速記

┌──────────────────────────────────────────────────────┐
│                 本週 SQL 知識地圖                       │
├──────────────────────────────────────────────────────┤
│                                                        │
│  Day 1:SELECT, FROM, WHERE, ORDER BY, DISTINCT, AS   │
│  Day 2:BETWEEN, IN, LIKE, AND/OR, LIMIT, CASE WHEN   │
│  Day 3:COUNT/SUM/AVG/MAX/MIN, GROUP BY, HAVING, 子查詢│
│  Day 4:INNER JOIN, LEFT JOIN, VIEW                    │
│  Day 5:INSERT, UPDATE, DELETE, Transaction, INDEX     │
│  Day 6:30 題整合練習 + 面試加分題                      │
│                                                        │
│  ★ 高頻考點:                                          │
│  1. WHERE vs HAVING                                    │
│  2. INNER JOIN vs LEFT JOIN                            │
│  3. UPDATE/DELETE 要加 WHERE                           │
│  4. 子查詢(找最高薪、高於平均)                         │
│  5. GROUP BY + 聚合函數                                │
│  6. SQL 執行順序                                       │
└──────────────────────────────────────────────────────┘

2.3 語法速查表

功能 語法 範例
查詢 SELECT ... FROM ... SELECT name FROM employees
篩選 WHERE WHERE salary > 50000
排序 ORDER BY ... ASC/DESC ORDER BY salary DESC
取前 N LIMIT N LIMIT 3
去重複 DISTINCT SELECT DISTINCT department
別名 AS salary AS 薪水
模糊查 LIKE WHERE name LIKE '王%'
範圍 BETWEEN ... AND ... BETWEEN 45000 AND 55000
清單 IN (...) IN ('IT','維修')
聚合 COUNT/SUM/AVG/MAX/MIN COUNT(*), AVG(salary)
分組 GROUP BY GROUP BY department
分組篩選 HAVING HAVING COUNT(*) > 1
關聯 JOIN ... ON JOIN departments d ON e.dept_id = d.id
左關聯 LEFT JOIN LEFT JOIN ... ON ...
條件值 CASE WHEN ... THEN ... END CASE WHEN salary>50000 THEN '高' END
新增 INSERT INTO INSERT INTO employees VALUES (...)
更新 UPDATE ... SET ... WHERE UPDATE employees SET salary=60000 WHERE id=1
刪除 DELETE FROM ... WHERE DELETE FROM employees WHERE id=1
建索引 CREATE INDEX CREATE INDEX idx ON employees(department)
建檢視 CREATE VIEW CREATE VIEW v AS SELECT ...
子查詢 (SELECT ...) WHERE salary > (SELECT AVG(salary) FROM ...)

三、手寫測驗(不看工具,紙上寫)

基礎篇(Q1~Q5)

Q1. 查 IT 部門薪水前 5 高(姓名、薪水)。

Q2. 統計每個部門的人數與平均薪水。

Q3. 查 2024 年以後到職的員工。

Q4. 用 JOIN 顯示每位員工的姓名與部門名稱。

Q5. 把 id=3 的員工薪水改成 50000。

進階篇(Q6~Q10)

Q6. 查出薪水高於全公司平均的員工(用子查詢)。

Q7. 用 CASE WHEN 將員工依薪水分為高/中/低三級。

Q8. 查出每個部門薪水最高的員工姓名。

Q9. 找出沒有員工的部門(用 LEFT JOIN)。

Q10. 建立一個 VIEW 顯示員工姓名、薪水、部門名稱,然後查詢薪水大於 50000 的資料。

參考解答
-- Q1:IT 部門薪水前 5 高
SELECT name, salary FROM employees
WHERE department = 'IT'
ORDER BY salary DESC LIMIT 5;

-- Q2:每部門人數與平均薪水
SELECT department, COUNT(*) AS 人數, AVG(salary) AS 平均薪水
FROM employees GROUP BY department;

-- Q3:2024 年以後到職
SELECT name, hire_date FROM employees
WHERE hire_date >= '2024-01-01';

-- Q4:JOIN 顯示員工與部門名稱
SELECT e.name, d.dept_name
FROM employees e JOIN departments d ON e.dept_id = d.id;

-- Q5:更新薪水(含安全確認)
-- 先確認:SELECT * FROM employees WHERE id = 3;
UPDATE employees SET salary = 50000 WHERE id = 3;

-- Q6:薪水高於平均(子查詢)
SELECT name, salary FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- Q7:CASE WHEN 薪資分級
SELECT name, salary,
  CASE
    WHEN salary >= 55000 THEN '高薪'
    WHEN salary >= 48000 THEN '中薪'
    ELSE '一般'
  END AS 薪資等級
FROM employees;

-- Q8:每部門薪水最高的員工
SELECT e.name, e.department, e.salary
FROM employees e
WHERE e.salary = (
  SELECT MAX(salary) FROM employees
  WHERE department = e.department
);

-- Q9:沒有員工的部門
SELECT d.dept_name
FROM departments d
LEFT JOIN employees e ON e.dept_id = d.id
WHERE e.id IS NULL;

-- Q10:建立 VIEW 並查詢
CREATE VIEW v_emp_info AS
SELECT e.name AS 姓名, e.salary AS 薪水, d.dept_name AS 部門
FROM employees e
JOIN departments d ON e.dept_id = d.id;

SELECT * FROM v_emp_info WHERE 薪水 > 50000;

四、面試口述演練

4.1 被問「查 IT 部門薪水前 5 高怎麼寫」

邊講邊寫: 「我會先 FROM employees,然後 WHERE department = 'IT' 篩選 IT 部門,再 ORDER BY salary DESC 依薪水由高到低排序,最後 LIMIT 5 取前 5 名。SELECT 的部分選 name 和 salary。」

加分:主動提到「不同資料庫取前 N 名語法不同,MySQL/SQLite 用 LIMIT,SQL Server 用 TOP,Oracle 用 FETCH FIRST」。

4.2 被問「WHERE 和 HAVING 差在哪」

「WHERE 是在分組前篩選個別資料列,不能用聚合函數;HAVING 是在 GROUP BY 分組後篩選分組結果,可以用聚合函數。」 「例如我要找人數超過 3 人的部門,不能用 WHERE COUNT()>3,要用 HAVING COUNT()>3。」

4.3 被問「INNER JOIN 和 LEFT JOIN 差在哪」

「INNER JOIN 只回傳兩邊都對得上的資料,LEFT JOIN 保留左表全部資料,右表沒對到的補 NULL。」 「例如我要列出所有部門包含沒有員工的,就要用 LEFT JOIN。」

4.4 被問「UPDATE 要注意什麼」

「最重要的是一定要加 WHERE 條件,不然會更新整張表。我的習慣是先用 SELECT + 同樣的 WHERE 確認影響範圍,確認只有要改的那幾筆後,再把 SELECT 改成 UPDATE。」 「在正式環境會先 BEGIN TRANSACTION,確認結果正確再 COMMIT,做錯了可以 ROLLBACK。」

4.5 被問「什麼是 INDEX」

「INDEX 像書的目錄,讓資料庫不用掃描整張表就能快速定位資料。通常在 WHERE、JOIN、ORDER BY 常用的欄位上建立。」 「但 INDEX 不是越多越好,因為每次 INSERT/UPDATE/DELETE 都要同步更新索引,會拖慢寫入效能。」


五、常見誤解總整理

誤解 正確觀念
「SQL 語法順序就是執行順序」 寫的順序是 SELECT→FROM→WHERE,但執行順序是 FROM→WHERE→SELECT
「手寫 SQL 不重要」 面試白板題就是考手寫,要能不看工具寫出正確的 SQL
「會 SELECT 就夠了」 還要會 UPDATE/DELETE(含安全習慣)、子查詢、JOIN、GROUP BY
「背語法就好」 理解概念更重要,例如 WHERE vs HAVING 的差異

六、面試加分小知識

  • Explain Plan:用 EXPLAIN 查看查詢執行計畫,了解資料庫如何處理你的 SQL。
  • 正規化(Normalization):把資料拆到多張表避免重複,1NF/2NF/3NF 是三個層級。
  • 反正規化(Denormalization):為了查詢效能,有時會故意保留一些重複資料。
  • Stored Procedure(預存程序):把常用的 SQL 邏輯存在資料庫中,可重複呼叫。
  • Trigger(觸發器):當資料被 INSERT/UPDATE/DELETE 時自動執行的 SQL。
  • ORM(Object-Relational Mapping):用程式語言的物件操作資料庫,不直接寫 SQL(如 Django ORM、SQLAlchemy)。但面試通常要求你會「原生 SQL」。

七、自我評估檢查表

完成以下每項確認你的 SQL 能力:

能力 我能不看答案寫出來嗎?
SELECT + WHERE + ORDER BY
BETWEEN / IN / LIKE
AND / OR(含括號)
LIMIT(取前 N)
DISTINCT / AS
COUNT / SUM / AVG / MAX / MIN
GROUP BY + HAVING
INNER JOIN
LEFT JOIN
子查詢(WHERE 裡的 subquery)
CASE WHEN
INSERT / UPDATE / DELETE
UPDATE/DELETE 前先 SELECT 確認
VIEW 建立與使用
INDEX 觀念
說出 SQL 執行順序
口述 WHERE vs HAVING 差異
口述 INNER JOIN vs LEFT JOIN 差異

目標:全部打勾才算準備好面試。


八、延伸閱讀


九、本週結算檢核

  • [ ] 手寫測驗 10 題全對(基礎 5 + 進階 5)
  • [ ] 完成 30 題實戰(Day 6)
  • [ ] 挑戰面試加分題(Day 6 的 31~40)
  • [ ] 能說出 SQL 執行順序
  • [ ] 能口述常見查詢的寫法
  • [ ] 自我評估檢查表全部打勾

完成 → 第 6 週(SQL 重點)結束!下週進入自動化與知識管理。


⬅️ 上一天:Day 6 | 🏠 本週總覽 | ➡️ 下一週:第 7 週 Day 1