本日主題:修改資料庫內容,並建立安全習慣 + 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,加索引效益不大)

六、延伸閱讀


七、今日檢核

  • [ ] 我會 INSERT / UPDATE / DELETE
  • [ ] 我養成改/刪前先 SELECT 確認的習慣
  • [ ] 我知道漏 WHERE 的嚴重後果
  • [ ] 我理解 Transaction 與 ACID
  • [ ] 我理解 INDEX 的作用與適用場景

⬅️ 上一天:Day 4 | 🏠 本週總覽 | ➡️ 下一天:Day 6 — 30 題實戰演練