想象一下,我们有两个表格:一个是学生表(记录了学生的基本信息,比如姓名、年龄),另一个是成绩表(记录了每个学生的考试分数)。如果我们想知道每个学生的具体分数,就需要把这两个表格的数据“拼”在一起——这就是MySQL的JOIN操作要做的事情!

1. 先了解表结构

假设我们有两个表:
- 学生表(students):记录学生的ID和基本信息
| id | name | age |
|-----|------|-----|
| 1 | 小明 | 18 |
| 2 | 小红 | 19 |
| 3 | 小刚 | 17 |
| 4 | 小强 | 18 |

  • 成绩表(scores):记录学生的分数,通过 student_id 关联到学生表
    | id | student_id | score |
    |-----|------------|-------|
    | 1 | 1 | 90 | (小明的分数)
    | 2 | 2 | 85 | (小红的分数)
    | 3 | 3 | 78 | (小刚的分数)
    | 4 | 5 | 95 | (student_id=5的学生分数,但学生表中没有该学生)

2. 内连接(INNER JOIN)

什么是内连接?
内连接只返回两个表中同时存在匹配记录的行(“两边都有的数据才显示”)。

语法格式

SELECT 列名 FROM 1 INNER JOIN 2 ON 1.关联字段 = 2.关联字段;

INNER JOIN 可简化为 JOIN,效果相同)

例子
查看所有有分数记录的学生姓名和分数:

SELECT students.name, scores.score 
FROM students 
INNER JOIN scores 
ON students.id = scores.student_id;

结果集
只包含两表匹配的记录(小明、小红、小刚):
| name | score |
|------|-------|
| 小明 | 90 |
| 小红 | 85 |
| 小刚 | 78 |

3. 左连接(LEFT JOIN)

什么是左连接?
左连接返回左表(左边的表)的所有记录,右表中没有匹配的部分用 NULL 填充。

语法格式

SELECT 列名 FROM 1 LEFT JOIN 2 ON 1.关联字段 = 2.关联字段;

例子
查看所有学生的姓名和分数(包括没分数的学生):

SELECT students.name, scores.score 
FROM students 
LEFT JOIN scores 
ON students.id = scores.student_id;

结果集
左表(students)所有学生都保留,右表无匹配则 NULL
| name | score |
|------|-------|
| 小明 | 90 |
| 小红 | 85 |
| 小刚 | 78 |
| 小强 | NULL |

4. 右连接(RIGHT JOIN)

什么是右连接?
右连接返回右表(右边的表)的所有记录,左表中没有匹配的部分用 NULL 填充。

语法格式

SELECT 列名 FROM 1 RIGHT JOIN 2 ON 1.关联字段 = 2.关联字段;

例子
查看所有分数记录对应的学生姓名(包括无学生的分数):

SELECT students.name, scores.score 
FROM students 
RIGHT JOIN scores 
ON students.id = scores.student_id;

结果集
右表(scores)所有记录都保留,左表无匹配则 NULL
| name | score |
|------|-------|
| 小明 | 90 |
| 小红 | 85 |
| 小刚 | 78 |
| NULL | 95 |

5. 全连接(FULL JOIN)

注意:MySQL本身不支持 FULL JOIN,需用 LEFT JOIN + UNION 模拟。

语法示例

(SELECT students.name, scores.score 
 FROM students 
 LEFT JOIN scores ON students.id = scores.student_id)
UNION
(SELECT students.name, scores.score 
 FROM students 
 RIGHT JOIN scores ON students.id = scores.student_id)
WHERE students.name IS NOT NULL OR scores.score IS NOT NULL;

结果集
包含所有学生和所有分数,无匹配部分用 NULL
| name | score |
|------|-------|
| 小明 | 90 |
| 小红 | 85 |
| 小刚 | 78 |
| 小强 | NULL |
| NULL | 95 |

6. 常见问题与注意事项

  • 必须写 ON 子句吗?
    必须!ON 指定连接条件(如 students.id = scores.student_id),否则 INNER JOIN 会变成笛卡尔积(结果行数=左表行数×右表行数,通常错误)。

  • 连接条件写错怎么办?
    ON 条件错误(如写成 students.id = scores.id),关联失败,结果可能为空或数据错误。

  • 如何筛选 NULL 值?
    想找“没分数的学生”:

  SELECT students.name 
  FROM students 
  LEFT JOIN scores ON students.id = scores.student_id 
  WHERE scores.score IS NULL; -- 只显示小强

总结

  • INNER JOIN:只保留两表匹配记录(推荐:需同时存在两表数据时用)
  • LEFT JOIN:保留左表全部,右表无匹配则 NULL(推荐:需保留主表全部数据时用)
  • RIGHT JOIN:保留右表全部,左表无匹配则 NULL(推荐:需保留从表全部数据时用)

记住“左表保留全部,右表按需匹配”,就能轻松掌握JOIN的核心逻辑!

小夜