数据按「一件事一张表」拆开存,所以看全貌就得把表连起来。 连起来的本质是「按条件把行两两配对」。 不写配对条件就是笛卡儿积:12 个学生 × 3 个班 = 36 行, 其中只有 12 行是真的同班,其余全是乱配。 四类连法:内连接(两边都配上)、外连接(一边没配上也要留)、 笛卡儿积(直接全配)、自连接(一张表跟自己连)。
前九章全在「一张表以内」打转。 这一章第一次让两张表见面,也是全书的分水岭。 为什么前面要拆表: 不拆就会有大量重复—— 每个学生都存一遍班级名和班主任,改一个老师要改几十行。 拆开是一张表一件事,代价是查的时候要连。
一、单表查询的天花板
学生表里只有 class_id(数字),没有班级名、没有老师名。
想知道「张伟在哪个班、班主任是谁」,这一张表答不了。
这是拆表的必然结果:
班级信息在 classes、学生信息在 students、成绩在 scores。
每张表只管一件事,所以任何一件「跨了两件事」的问题,都要连表。
合起来存行不行:能跑,但会有大量重复。
三个班 12 个学生,班级名和老师名各存 12 遍;老师一换,12 行都得改,漏一行就自相矛盾。
这就是数据库设计里说的「冗余」。
二、连起来的本质:配对
两个表连起来,就是「按某个条件把行两两配对」。
条件写 s.class_id = c.id,意思就是「学生的班级号等于班级的编号」。
配上的行合成一行,于是「班级名」「班主任」这些本来在另一张表里的列,
就能跟学生信息出现在同一行里了。
所以连表的关键永远是「两个表的哪些列能对上」——这就是外键存在的意义:
它明确告诉你 students.class_id 指向 classes.id,不用猜。
第 9.8 篇讲的外键,在这里兑现了它的价值。
三、不写配对条件会怎样:36 行
FROM students, classes 不写 where,给 36 行。
12 个学生 × 3 个班,每一行都跟对方每一行配了一次。 这叫「笛卡儿积」。
其中只有 12 行是「真的同班」,其余 24 行都是乱配的。 但它不报错——
这是多表查询最经典的错误:结果行数暴增,看着像「数据变多了」,实际全是垃圾。
排查办法很土但很有效:
先单独 count(*) 两张表,再 count(*) 连完的结果,对不上就是条件写错或漏写了。
四、四类连法,先记住名字
内连接:只留「两边都配上」的行。这是最常用的,占实际工作的八成以上。 外连接:留「一边没配上」的行,另一边的列填 NULL。 分左外、右外、完全外三种。 笛卡儿积连接:不做配对、直接全配。除了算组合和造日历,基本是错误。 自连接:一张表跟自己连,靠两个别名区分。 处理「同一类东西之间的关系」——上下级、同班同学、相邻两天。
五、本章六篇怎么排
10.2 集合运算 → 10.3 内连接 → 10.4 外连接 → 10.5 笛卡儿积 → 10.6 自连接。 集合运算是「上下拼」:把两个结果摞起来,列不变、行变多。 连接是「左右拼」:把两边的列并到一行里,列变多。 这两件事经常被混为一谈,其实完全不同。 一个改行、一个改列,用错场景时结果会非常奇怪。
六、动手 Demo:单表的天花板、一次成功配对、一次 36 行的乱配
Demo 四段:先看单表能给出什么,再把学生表和班级表按 class_id 配对,然后故意不写条件,
看 36 行是怎么来的,最后过一遍四类连法。
第三段那个 36 行是全篇的重点——它说明「连表出错」不会报错,只会让数字变大。
import _q46 as Q
c = Q.con()
# 单表只能看到班级号,看不到班级名
Q.show(c, "SELECT id, name, class_id FROM students LIMIT 3")
# 连起来:按 s.class_id = c.id 配对
Q.show(c, "SELECT s.name AS 学生, c.name AS 班级, c.teacher AS 班主任 "
"FROM students s JOIN classes c ON s.class_id = c.id LIMIT 4")
# 不写配对条件:12 x 3 = 36 行
Q.show(c, "SELECT COUNT(*) AS rows_no_on FROM students, classes")
实跑输出:
--------------------------------------------------------------------
第五十二课:一张表看不全,所以要把表连起来
--------------------------------------------------------------------
单表查询的天花板
SQL> SELECT id, name, class_id FROM students LIMIT 3
id name class_id
-------------------------
1 张伟 1
2 王芳 1
3 李娜 2
(3 行)
**学生表里只有 `class_id`,没有班级名、没有老师名。**
**想知道「张伟在哪个班、班主任是谁」,这张表答不了。**
**数据是按「一件事一张表」拆开存的**:
**班级的信息在 `classes`、学生的信息在 `students`、成绩在 `scores`。**
**拆开的好处是不重复、改一处就够;代价是要看全貌就得连起来。**
连起来的本质:配对
**两个表连起来,就是「按某个条件把行两两配对」。**
**条件写 `s.class_id = c.id`,意思就是「学生的班级号 等于 班级的编号」。**
SQL> SELECT s.name AS 学生, c.name AS 班级, c.teacher AS 班主任 FROM students s JOIN classes c
ON s.class_id = c.id LIMIT 4
学生 班级 班主任
-------------------------
张伟 一班 马老师
王芳 一班 马老师
李娜 二班 孔老师
刘洋 二班 孔老师
(4 行)
**一行学生配上了一行班级**,于是「班级名」和「班主任」都能拿出来了。
不写配对条件会怎样:36 行
SQL> SELECT COUNT(*) AS rows_no_on FROM students, classes
rows_no_on
-----------
36
(1 行)
**12 个学生 × 3 个班 = 36 行。** **这叫「笛卡儿积」——每一行都跟对方每一行配了一次。**
**其中只有 12 行是「真的同班」,其余 24 行都是乱配的。**
**这是多表查询最经典的错误**:忘了写条件,
**结果不报错、行数暴增,看着像「数据变多了」,实际全是垃圾。**
三种连接,先记住名字
**内连接**:只留「两边都配上」的行。**这是最常用的。**
**外连接**:留「一边没配上」的行,另一边的列填 NULL。 **分左外、右外、完全外三种。**
**笛卡儿积连接**:不做配对、直接全配。**除了算组合,基本是错误。**
**外加一种「自连接」**:**一张表跟自己连**,用来处理「同一类东西之间的关系」。
**这一章六篇就是这四类。**
本章六篇怎么排
**10.2 集合运算 → 10.3 内连接 → 10.4 外连接 → 10.5 笛卡儿积 → 10.6 自连接。**
**集合运算是「上下拼」**(把两个结果摞起来),**连接是「左右拼」**(把两边的列并到一行)。
**这两件事经常被混为一谈,其实完全不同。**
第一段三行学生,只有 class_id,没有班级名和老师名。
第二段配对成功,四行结果里班级名和班主任都出来了。
第三段 36 行:12 × 3,只有三分之一是真的同班。
后三段没有 SQL,讲四类连法和这一章的篇目顺序。
30 秒实验
- 为什么学生表里不直接存班级名和班主任?那样不是更省事吗?
SELECT * FROM students, classes会给出几行?为什么?- 集合运算和连接,一个改行一个改列——各举一个该用的场景。
常见误区
- 连表忘写配对条件。 不报错,只是行数变成乘积,报表数字凭空变大。
- 把集合运算当连接用。
UNION是上下摞行,不会把两边的列并到一行,需求会完全走偏。 - 以为「连表越多越强」。 每多一张表就多一次配对,条件漏一个行数就炸一次。该分步查的就分步。
自测三问(点开对答案)
1. 为什么要把数据拆成多张表?代价是什么? —— 拆开避免冗余,改一处就够;代价是查跨表信息时必须连表,写起来更复杂。 2. 两个表连起来的本质是什么? —— 按某个条件把行两两配对,配上之后两边的列就能出现在同一行里。 3. 四类连法分别是什么? —— 内连接(只留两边都配上的)、外连接(一边没配上也要留)、笛卡儿积(直接全配)、 自连接(自己跟自己连)。先讲一个跟连接完全不同、但经常被混进来的东西: 下一篇 10.2 集合运算——把两个结果上下摞起来。
- ☐ (本篇完,下一篇 10.2 集合运算)