本日主題:修改資料庫內容,並建立安全習慣 + INDEX 觀念 預計時間:1.5 小時 對應主教材:第 6.1 節
一、今日學習目標
- [ ] 會新增、更新、刪除資料
- [ ] 建立「改/刪前先確認」的安全習慣
- [ ] 認識 Transaction(交易)觀念
- [ ] 理解 INDEX(索引)的觀念
- [ ] 會用 INSERT INTO ... SELECT 批量複製
二、教材內容
2.1 INSERT 新增
-- 方法 1:指定欄位(推薦,清楚且不怕欄位順序變動)
INSERT INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (7, '吳俊傑', 'IT', 1, 50000, '2025-05-01');
-- 方法 2:一次插入多筆
INSERT INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES
(8,'蔡宜芳','會計',2,46000,'2025-04-01'),
(9,'鄭文彬','維修',3,49000,'2025-03-15');
-- 方法 3:從另一張表複製資料
INSERT INTO employees_backup
SELECT * FROM employees WHERE department = 'IT';
常見錯誤示範:
-- ❌ 錯誤 1:值的數量跟欄位不符
INSERT INTO employees (id, name, department)
VALUES (10, '測試員'); -- 只給 2 個值,但指定 3 個欄位
-- ❌ 錯誤 2:主鍵重複
INSERT INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (1, '新員工', 'IT', 1, 50000, '2025-06-01');
-- id=1 已經存在,會報 PRIMARY KEY 衝突
-- ❌ 錯誤 3:不指定欄位直接插入(不推薦)
INSERT INTO employees VALUES (10, '測試', 'IT', 1, 50000, '2025-06-01');
-- 如果表的欄位順序改了,資料會插錯欄位
2.2 UPDATE 更新(⚠️ 一定要加 WHERE)
-- 改單一欄位
UPDATE employees
SET salary = 53000
WHERE id = 7; -- 只改 id=7 這個人
-- 改多個欄位
UPDATE employees
SET salary = 53000, department = '維修', dept_id = 3
WHERE id = 7;
-- 用計算式更新
UPDATE employees
SET salary = salary + 3000 -- 加薪 3000
WHERE department = 'IT';
致命錯誤:忘記加 WHERE:
sql -- ❌ 致命錯誤!全公司薪水都變 53000! UPDATE employees SET salary = 53000;
錯誤示範與後果:
-- ❌ 錯誤 1:WHERE 條件太寬(改到不該改的)
UPDATE employees SET salary = 60000
WHERE department = 'IT'; -- 整個 IT 部門都變 60000
-- ❌ 錯誤 2:漏掉 WHERE(整表被改)
UPDATE employees SET department = '維修';
-- 全公司所有人都變成維修部門!
-- 正確做法:先 SELECT 確認影響範圍
SELECT * FROM employees WHERE id = 7; -- 確認只有 1 筆
UPDATE employees SET salary = 53000 WHERE id = 7;
2.3 DELETE 刪除(⚠️ 同樣要加 WHERE)
DELETE FROM employees WHERE id = 9; -- 只刪 id=9
-- ❌ 危險!不加 WHERE = 整張表清空!
-- DELETE FROM employees;
-- TRUNCATE vs DELETE:
-- DELETE:逐列刪除,可搭配 WHERE,可 ROLLBACK
-- TRUNCATE:整表快速清空,不可加 WHERE,不可 ROLLBACK(某些資料庫)
2.4 安全習慣(實務超重要)
┌──────────────────────────────────────────────────┐
│ UPDATE / DELETE 安全三步驟 │
├──────────────────────────────────────────────────┤
│ │
│ Step 1:先用 SELECT 確認範圍 │
│ SELECT * FROM employees WHERE id = 7; │
│ → 確認只有這 1 筆是你要改/刪的 │
│ │
│ Step 2:確認 OK 再執行 UPDATE/DELETE │
│ UPDATE employees SET salary = 53000 WHERE id = 7; │
│ │
│ Step 3:再 SELECT 一次驗證結果 │
│ SELECT * FROM employees WHERE id = 7; │
│ → 確認已正確修改 │
│ │
│ ★ 正式環境:包在 Transaction 裡 │
└──────────────────────────────────────────────────┘
2.5 Transaction(交易)觀念
Transaction 讓你可以「反悔」:
-- 開始交易
BEGIN TRANSACTION;
-- 執行更新
UPDATE employees SET salary = 53000 WHERE id = 7;
-- 檢查結果
SELECT * FROM employees WHERE id = 7;
-- 確認 OK → 提交(永久生效)
COMMIT;
-- 發現做錯了 → 回滾(撤銷所有變更)
-- ROLLBACK;
Transaction 的 ACID 特性(面試考點):
| 特性 | 英文 | 說明 |
|---|---|---|
| 原子性 | Atomicity | 要嘛全成功,要嘛全失敗 |
| 一致性 | Consistency | 交易前後資料保持一致 |
| 隔離性 | Isolation | 多個交易互不干擾 |
| 持久性 | Durability | 提交後永久保存 |
2.6 INDEX(索引)觀念
INDEX 就像書的目錄,加快查詢速度:
-- 建立索引
CREATE INDEX idx_department ON employees(department);
CREATE INDEX idx_salary ON employees(salary);
-- 複合索引(多欄位)
CREATE INDEX idx_dept_salary ON employees(department, salary);
-- 查看索引(SQLite)
.indices employees
-- 刪除索引
DROP INDEX idx_department;
INDEX 圖解:
┌──────────────────────────────────────────────┐
│ 沒有索引 vs 有索引 │
├──────────────────────────────────────────────┤
│ │
│ 沒索引:WHERE department = 'IT' │
│ → 掃描全部 10000 筆找出 IT(全表掃描) │
│ → 慢 🐢 │
│ │
│ 有索引:WHERE department = 'IT' │
│ → 先查索引,直接定位 IT 的資料位置 │
│ → 快 🚀 │
│ │
│ 類比: │
│ 沒索引 = 整本書翻過找一個詞 │
│ 有索引 = 看目錄翻到對的頁碼 │
└──────────────────────────────────────────────┘
INDEX 使用原則:
| 建議加 INDEX 的欄位 | 不建議加 INDEX 的欄位 |
|---|---|
| WHERE 常用的篩選欄位 | 很少用在 WHERE 的欄位 |
| JOIN 的關聯欄位(Foreign Key) | 值很少變化的欄位(如只有 M/F) |
| ORDER BY 常排序的欄位 | 資料量很小的表 |
| 唯一識別的欄位(如 email) | 經常被 INSERT/UPDATE/DELETE 的表 |
注意:INDEX 加速查詢,但會拖慢 INSERT/UPDATE/DELETE(因為要同步更新索引)。不是越多越好。
2.7 REPLACE 與 UPSERT
-- REPLACE INTO(SQLite/MySQL):有就更新,沒有就新增
REPLACE INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (7, '吳俊傑', 'IT', 1, 55000, '2025-05-01');
-- INSERT OR IGNORE(SQLite):主鍵衝突就忽略
INSERT OR IGNORE INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (1, '重複的', 'IT', 1, 50000, '2025-06-01');
-- id=1 已存在,這筆會被忽略,不會報錯
三、常見誤解
| 誤解 | 正確觀念 |
|---|---|
| 「DELETE 就是永久刪除」 | 在 Transaction 中,DELETE 可以 ROLLBACK 恢復 |
| 「INDEX 越多越好」 | INDEX 加速查詢但拖慢寫入,要根據實際查詢需求決定 |
| 「TRUNCATE 和 DELETE 一樣」 | TRUNCATE 更快但不能加 WHERE 且通常不可 ROLLBACK |
| 「UPDATE 不加 WHERE 會報錯」 | 不會報錯!會直接更新整張表所有資料,非常危險 |
四、面試加分小知識
- Soft Delete(軟刪除):不真的刪除資料,而是加一個
is_deleted欄位標記。企業常用,方便追蹤與恢復。 - Audit Trail(稽核軌跡):記錄誰在什麼時間做了什麼異動,合規要求。
- Clustered Index vs Non-Clustered Index:聚集索引決定資料實體排列順序(每表只能一個),非聚集索引是獨立的索引結構。
- EXPLAIN:查看 SQL 的執行計畫,了解查詢是否用到索引。
- Deadlock(死鎖):兩個交易互相等待對方釋放資源,導致雙方都卡住。
五、今日練習
Q1. 新增一名員工(自訂資料)。
Q2. 把某位員工的薪水調整為 58000(指定一個 id)。
Q3. 刪除某一位員工,並說明你會先做什麼確認。
Q4. 解釋 Transaction 的用途,以及 COMMIT 和 ROLLBACK 的差別。
Q5. 解釋 INDEX 的作用,以及什麼時候不應該加 INDEX。
參考解答
-- A1:新增員工
INSERT INTO employees (id, name, department, dept_id, salary, hire_date)
VALUES (10, '測試員', 'IT', 1, 50000, '2025-06-01');
-- A2:調整薪水
-- Step 1: 先確認
SELECT * FROM employees WHERE id = 10;
-- Step 2: 更新
UPDATE employees SET salary = 58000 WHERE id = 10;
-- Step 3: 驗證
SELECT * FROM employees WHERE id = 10;
-- A3:刪除員工
-- 先 SELECT 確認只命中要刪的那筆
SELECT * FROM employees WHERE id = 10;
-- 確認後再刪除
DELETE FROM employees WHERE id = 10;
-- 再確認已刪除
SELECT * FROM employees WHERE id = 10; -- 應該沒有結果
**A4.** Transaction 的用途是把多個 SQL 操作包成一個「原子操作」,要嘛全成功,要嘛全失敗。
- **COMMIT**:確認所有變更,永久寫入資料庫
- **ROLLBACK**:撤銷所有變更,恢復到 BEGIN TRANSACTION 之前的狀態
- 用途:在正式環境做 UPDATE/DELETE 時,先 BEGIN TRANSACTION,確認結果正確再 COMMIT,做錯了可以 ROLLBACK
**A5.** INDEX 像書的目錄,讓資料庫不用掃描整張表就能快速定位資料。
不應該加 INDEX 的情況:
1. 資料量很小的表(全表掃描可能更快)
2. 很少用在 WHERE/JOIN/ORDER BY 的欄位
3. 經常大量 INSERT/UPDATE/DELETE 的表(索引維護成本高)
4. 欄位值的種類很少(如性別只有 M/F,加索引效益不大)
六、延伸閱讀
- SQL Transaction (W3Schools) — Transaction 教學
- SQL Index (W3Schools) — INDEX 教學
- Use The Index, Luke — 深入了解索引的經典網站
七、今日檢核
- [ ] 我會 INSERT / UPDATE / DELETE
- [ ] 我養成改/刪前先 SELECT 確認的習慣
- [ ] 我知道漏 WHERE 的嚴重後果
- [ ] 我理解 Transaction 與 ACID
- [ ] 我理解 INDEX 的作用與適用場景
⬅️ 上一天:Day 4 | 🏠 本週總覽 | ➡️ 下一天:Day 6 — 30 題實戰演練