# P37 37. 基础-多表查询-多表关系介绍

> 本页是学习笔记，不等同于视频逐字稿。原声字幕未取得（匿名接口字幕轨为空且需登录，未使用任何账号），也没有逐句讲解记录；讲义只按节与页码对应，切点未逐句确证。

> 以同版讲义的公开镜像核对章节与页码（镜像非官方出品）；非逐字稿，示例为原创补充。

## P37 37. 基础-多表查询-多表关系介绍

- 原视频：https://www.bilibili.com/video/BV1Kr4y1i7ru/?p=37（p=37），时长 12:12
- 讲义：5.1 多表关系（一对多 / 多对多 / 一对一） p69–72（公开镜像；按主题对应，切点 notexact）

- 本集练习数据：practice/p37.sql（先执行，再对照小例）

### 一句话理解

表之间的关系就三种：一对一、一对多、多对多。判断方法很实在——看外键放在哪张表、要不要第三张中间表。

### 跟播：视频里 ↔ 本站

视频用 emp / dept 讲一对多、多对多、一对一三种关系，重点是外键放哪张表。

| 视频里 / 原课字段 | 本站对应 |
|---|---|
| 讲义 emp 17 行、8 列（含 job / entrydate / managerid） | 本站 employee 4 行、6 列（含 manager_id，没有 job / entrydate） |
| 讲义 dept 6 行：1 研发部、2 市场部、3 财务部… | 本站 department 3 行：1 研发部、2 测试部、3 运营部（2 号名字不同） |

看完应能：看到「一个部门多个员工」能立刻说出外键放 employee 这一侧

看视频时以讲义 emp/dept 为准，跟练时用本站 employee/department；表名与数字都不同，结构对应即可。

### 步骤

1. 先数“谁多”。一个部门有多名员工，一名员工只属于一个部门，所以 employee 是“多”的一方，外键 dept_id 放这里。为什么：外键放多的一方，每条员工记录只能填一个部门号，重复是天然的。
2. 一对一用于拆表。比如员工表和员工档案表，两边都只对应一条；外键放任意一方，但要加 UNIQUE，否则会退化成一堆一对多。
3. 多对多必须建中间表。学生选课，一个学生选多门课，一门课被多人选；中间表放 student_id、course_id 两个外键，联合起来当主键，重复选课才插不进去。
4. 关系定完再写查询。一对多靠 dept_id = id 连两张表；多对多要连三张表；一对一多一次 join。连接条件不是猜的，是外键指出来的。

### SQL 示例

```
-- 本页练习用的建表段：在 mysqlnotes_p37 里执行一次（后面各页用各自的 pNN.sql，不复用这里）
-- department(1 研发部, 2 测试部, 3 运营部)
-- employee：小林22/研发8000/上级2，小周25/研发10000/无上级，小陈30/测试12000/上级2，小李21/无部门/NULL/上级2

CREATE TABLE department (
  id INT PRIMARY KEY,
  name VARCHAR(20) NOT NULL
);
CREATE TABLE employee (
  id INT PRIMARY KEY,
  name VARCHAR(20) NOT NULL,
  age INT,
  dept_id INT,
  salary INT,
  manager_id INT
);
INSERT INTO department VALUES (1,'研发部'),(2,'测试部'),(3,'运营部');
INSERT INTO employee VALUES
 (1,'小林',22,1,8000,2),
 (2,'小周',25,1,10000,NULL),
 (3,'小陈',30,2,12000,2),
 (4,'小李',21,NULL,NULL,2);

-- 一对多：外键放在“多”的一方
ALTER TABLE employee
  ADD CONSTRAINT fk_emp_dept
  FOREIGN KEY (dept_id) REFERENCES department(id);
```

说明：前面几段只建表灌数据；这两张表属于本页练习库 mysqlnotes_p37，后面各页用的是各自的 pNN.sql，列数和数据类型可能不同，别拿这里的 6 列结构去套别的页。最后一段给 employee.dept_id 加外键：以后 dept_id 只能填 1、2、3 或 NULL，写 99 会被拒绝。自检跑 SELECT id,name,dept_id FROM employee ORDER BY id，应得 4 行，小李的 dept_id 是 NULL——外键允许空值，不代表他有部门。

### 易错点

- 外键方向写反（在 department 里放 employee_id），一个部门只能记一个员工，一对多就装不下了。
- 多对多只在一边加外键，另一边的对应关系无处存放，迟早出现重复行。
- 外键列类型必须和被引用主键一致（INT 对 INT），类型不同建约束会失败。

### 30 秒速记

一对多：外键在多的一方；一对一：外键+UNIQUE；多对多：中间表两个外键；连接条件来自外键。

### 自测

1. 一个部门多名员工，外键该放哪张表？
   - 答：employee（多的一方），存 dept_id 指向 department.id；放反了一个部门只能挂一个员工。
2. 多对多的中间表为什么常把两个外键做成联合主键？
   - 答：防止同一对组合重复插入，同时天然形成“两个一对多”。

### 材料与来源

- [平台视频页] BV1Kr4y1i7ru P37（平台标题） https://www.bilibili.com/video/BV1Kr4y1i7ru/?p=37
- [官方文档] MySQL 8.0 Reference Manual — JOIN Clause https://dev.mysql.com/doc/refman/8.0/en/join.html

证据说明：本集无逐字稿（匿名 player/v2 返回 subtitles=[]、need_login_subtitle=true），依据平台标题、讲义 p69–72「5.1 多表关系」与公开静帧核对；多对多部分以 t≈292s 静帧（中间表）为准。一对一、一对多的表述为同主题通用整理。示例表与数据为本笔记自建，不是课程原表。
