🗄️ 第二章 数据的存储方式-关系型数据库的特征
📄 一句话概括

数据按主题拆成多张表,用的时候再按公共字段连接(join)回来——拆是为了不重复,连是为了用起来像一张表。

📝 本节和前面几节的关系

2-2 把一张表的解剖图摊平了;本节回答下一个自然的问题:【现实业务那么复杂,一张表装得下吗?】——装得下但不该装,答案是拆表 + 连接。这是全章最难的一节(⭐⭐⭐),也是关系模型的看家本领。

一、为什么要拆表

看反面教材——把订单信息全塞一张表:

订单号 顾客姓名 顾客电话 商品 金额
A001 张三 13800000001 台灯 59
A002 张三 13800000001 插座 29
A003 李四 13800000002 台灯 59

问题一眼可见:

  1. 重复:张三的电话存了两遍——他改个手机号,要改两处,漏改一处数据就不一致
  2. 浪费:同样两个字段的【台灯|59】也存了两遍
  3. 难改:商品降价要扫全表找【台灯】

拆表的动机就一句话:同一份信息只存一处,更新只改一处。(2-4 的【更新成本低】由此而来。)

二、怎么拆:主键与外键

按主题拆成三张表:

顾客表:

顾客ID(主键) 姓名 电话
1 张三 13800000001
2 李四 13800000002

商品表:

商品ID(主键) 商品名 价格
10 台灯 59
11 插座 29

订单表:

订单号(主键) 顾客ID(外键) 商品ID(外键)
A001 1 10
A002 1 11
A003 2 10

两个新词:

张三的电话现在只存一处(顾客表第 1 行);订单表只记【顾客 1】,不记电话。

三、连接:用的时候拼回来

月底想知道【谁买了什么】,把三张表按公共字段连接起来:

订单表 ⋈ 顾客表(订单.顾客ID = 顾客.顾客ID)
订单表 ⋈ 商品表(订单.商品ID = 商品.商品ID)

连出来的结果(一张【虚拟的宽表】,数据其实没动):

订单号 姓名 电话 商品名 金额
A001 张三 13800000001 台灯 59
A002 张三 13800000001 插座 29
A003 李四 13800000002 台灯 59

SQL 里就是一个词的事:JOIN ... ON ...(后面 SQL 章节细练)。

生活比喻:拆表像图书馆把书、借书人、借阅记录分开登记;连接像查一份借阅记录时,按借书证号把人名调出来、按书号把书名调出来——三本登记册各管各的,看的时候对一对号就拼成一条完整信息。

四、动手 Demo:拆表练习+一次手工连接

数据:王五在【会员表】(编号 3,电话 13800000003),他下了两单:【洗衣液】(商品 12,39 元)和【毛巾】(商品 13,15 元)。

  1. 写出三张表各需要哪几行:
  2. 会员表:3 | 王五 | 13800000003(1 行)
  3. 商品表:12 | 洗衣液 | 39、13 | 毛巾 | 15(2 行)
  4. 订单表:A004 | 3 | 12、A005 | 3 | 13(2 行)
  5. 手工连接:把王五两单拼成【订单号|姓名|商品|金额】的宽表
  6. 思考题:王五改电话号码,要改几处?——1 处(会员表一行);对比不拆表的情形是【下过几单改几处】

看到什么算成功:三张表拆得出、宽表拼得回、能答出【改电话只改一处】。

五、30 秒实验

打开购物网站的个人中心:

六、常见误区

  1. "拆表是为了省空间" —— 省空间是附带好处;真正动机是一致性:同一信息只存一处,改一处就处处对。
  2. "外键是订单表自己的编号" —— 不是。订单表自己的编号(A001)是主键;外键是借来别人表的主键(顾客ID),用途是指出【这行关联谁】。
  3. "连接会把数据物理上合成一张大表" —— 不会。连接是查询时刻的临时拼装,库里存的仍是三张小表;拼完的结果也不保存(除非你特意存)。
自测三问(点开对答案) 1. 拆表的动机一句话? **同一份信息只存一处,更新只改一处**——保证一致性。 2. 主键和外键分别是什么? **主键=本表唯一标识一条记录的字段;外键=本表里引用的别人表的主键**。 3. 连接按什么对号? **公共字段**——通常是【一张表的外键 = 另一张表的主键】。

相关笔记