INNER JOIN 內連接
為什麼需要 JOIN?
比喻:JOIN 就像合併兩份名冊 📋📋
你手上有一本「學生名冊」和一本「成績單」, 學號是它們的共同欄位——你用學號把兩本冊子的資料對在一起看, 這就是 JOIN。
兩張表的情境
Students 表 Courses 表
┌────┬──────┬─────┐ ┌────┬──────────┐
│ Id │ Name │ Age │ │ Id │ Name │
├────┼──────┼─────┤ ├────┼──────────┤
│ 1 │ 小明 │ 20 │ │ 10 │ 數學 │
│ 2 │ 小華 │ 22 │ │ 11 │ 英文 │
│ 3 │ 小美 │ 21 │ │ 12 │ 物理 │
└────┴──────┴─────┘ └────┴──────────┘
Enrollments 表(選課記錄)
┌────┬───────────┬──────────┬───────┐
│ Id │ StudentId │ CourseId │ Score │
├────┼───────────┼──────────┼───────┤
│ 1 │ 1 │ 10 │ 85 │
│ 2 │ 1 │ 11 │ 92 │
│ 3 │ 2 │ 10 │ 78 │
└────┴───────────┴──────────┴───────┘
注意:小美(Id=3)沒有選課記錄。
INNER JOIN 語法
SELECT
s.Name AS 學生, -- ← s 是 Students 的別名
c.Name AS 課程, -- ← c 是 Courses 的別名
e.Score AS 分數 -- ← e 是 Enrollments 的別名
FROM Students s -- ← 主表,取別名 s
INNER JOIN Enrollments e -- ← 連接選課表
ON s.Id = e.StudentId -- ← 連接條件:學生 Id 對應
INNER JOIN Courses c -- ← 再連接課程表
ON e.CourseId = c.Id; -- ← 連接條件:課程 Id 對應
逐行解析:
FROM Students s -- 起點:Students 表,別名 s
INNER JOIN Enrollments e -- 連接 Enrollments 表,別名 e
ON s.Id = e.StudentId -- 連接條件:Students.Id = Enrollments.StudentId
-- 只有能配對的資料才會出現
INNER JOIN Courses c -- 再連接 Courses 表
ON e.CourseId = c.Id -- 連接條件:Enrollments.CourseId = Courses.Id
結果:
學生 | 課程 | 分數
------+------+------
小明 | 數學 | 85
小明 | 英文 | 92
小華 | 數學 | 78
注意:小美不在結果中,因為她沒有選課記錄(INNER JOIN 只保留能配對的)。
INNER JOIN 的視覺化
Students Enrollments
┌────┐ ┌────┐
│ 小明│─────────▶│ 記錄│ ✅ 配對成功 → 出現在結果
│ 小華│─────────▶│ 記錄│ ✅ 配對成功 → 出現在結果
│ 小美│ ✗ │ │ ❌ 沒配對 → 不出現
└────┘ └────┘
INNER JOIN = 交集(兩邊都有才算)
表別名的重要性
-- ❌ 不用別名,很長很痛苦
SELECT Students.Name, Courses.Name, Enrollments.Score
FROM Students
INNER JOIN Enrollments ON Students.Id = Enrollments.StudentId
INNER JOIN Courses ON Enrollments.CourseId = Courses.Id;
-- ✅ 用別名,簡潔清楚
SELECT s.Name, c.Name, e.Score
FROM Students s
INNER JOIN Enrollments e ON s.Id = e.StudentId
INNER JOIN Courses c ON e.CourseId = c.Id;
搭配 WHERE 使用
-- 查詢小明的所有課程和分數
SELECT s.Name, c.Name AS 課程, e.Score
FROM Students s
INNER JOIN Enrollments e ON s.Id = e.StudentId
INNER JOIN Courses c ON e.CourseId = c.Id
WHERE s.Name = '小明'; -- ← JOIN 後再用 WHERE 過濾
-- 查詢數學科分數 >= 80 的學生
SELECT s.Name, e.Score
FROM Students s
INNER JOIN Enrollments e ON s.Id = e.StudentId
INNER JOIN Courses c ON e.CourseId = c.Id
WHERE c.Name = '數學'
AND e.Score >= 80;
搭配 GROUP BY 使用
-- 每個學生的選課數和平均分
SELECT
s.Name AS 學生,
COUNT(*) AS 選課數,
ROUND(AVG(e.Score), 1) AS 平均分
FROM Students s
INNER JOIN Enrollments e ON s.Id = e.StudentId
GROUP BY s.Name
ORDER BY 平均分 DESC;
自連接(Self Join)
-- 員工表:每個員工有一個 ManagerId 指向同一張表
SELECT
emp.Name AS 員工,
mgr.Name AS 主管
FROM Employees emp
INNER JOIN Employees mgr -- ← 同一張表連接自己!
ON emp.ManagerId = mgr.Id;
💡 自連接常用於階層結構(員工→主管、留言→回覆等)。