判断标准只有一个 — 会不会出现多个
ERD 是画出一个服务管理哪些东西、这些东西彼此如何相连的图。它是 Entity Relationship Diagram 的缩写,一个管理对象(实体)在数据库里就成为一张像 Excel 表格一样的表。表里竖着的一格是列,横着的一行是一条数据。
课程用手机请柬服务来讲解。管理员登录后制作请柬。这里的管理对象有两个:管理员和请柬。请柬里的标题、日期、地点、留言、新郎姓名、新娘姓名不是需要单独管理的对象,而是请柬的属性,所以成为请柬表的列。
服务运转顺利,于是再加一个功能:让宾客留下「恭喜」之类的祝福语。祝福语要能新写、修改和删除。能不能把它作为列挂在请柬表上?
如果一张请柬只会有一条祝福语,挂上去也可以,没必要另建一张表。但一场婚礼会有很多宾客留言。一个格子只能放一个值,所以这种做法行不通。于是把祝福语拆成单独的表,再用连线和请柬相连。
课程强调的正是这种感觉:某个值只存在一个就是列,可能出现多个就是表。每次加功能时,先问这个值在一个对象上会挂几个。
[只有一条] invitations 表加一列
id title greeting
1 我们结婚了 恭喜
[有多条] 单独的 greetings 表
id invitation_id content
1 1 恭喜
2 1 祝你们幸福
3 1 新婚快乐1:N、父与子 — 读懂连线末端的符号
表与表之间的关系大多是 1:N,意思是一个对应多个。一位管理员制作多张请柬,一张请柬收到多条祝福语,两者都是 1:N。
一的一方叫父,多的一方叫子。请柬只认创建它的那一位管理员,所以管理员是父,请柬是子。子表里放一列记录父的 id。请柬表里的 admin_id、上面例子中祝福语表里的 invitation_id,就是这样的格子。这种指向另一张表某一行的列叫外键。
在 ERD 里,给有关系的两张表之间画一条线,用线末端的形状表示数量。一的一方是竖线,多的一方是线末端分成三叉的形状。它像鸟爪,所以叫鸦爪表示法。
是否必须存在也标在同一位置。必须有就是竖线,可以没有就是圆圈。管理员可能一张请柬都还没做,所以请柬一端是圆圈和三叉叠在一起。反过来,请柬没有管理员就不会产生,所以父的一端通常是两条竖线。
线末端的两个符号中,靠近表的那个表示最大数量,离表远的那个(靠线中间)表示最小数量。只要读懂 AI 画出的 ERD 上的这些符号,就能看出服务允许什么。
| 符号 | 位置 | 含义 |
|---|---|---|
| 竖线 | | 靠近表的一侧 | 最多一个 |
| 三叉 { | 靠近表的一侧 | 多个 |
| 竖线 | | 离表远的一侧 | 至少一个(必需) |
| 圆圈 o | 离表远的一侧 | 可以没有(可选) |
管理员 ||--o{ 请柬 一位管理员对应 0 张以上请柬
请柬 ||--o{ 祝福语 一张请柬对应 0 条以上祝福语
请柬 ||--o| 直播 一张请柬对应 0 个或 1 个链接只有一个却单独拆出来 — 可选的 1:1
这次是直播功能。它是为不能亲自到场的宾客直播婚礼的付费服务,所以有人申请,也有人不申请。一场婚礼的直播链接要么没有,要么只有一个,不需要多个。
这种关系叫 1:1,而且因为可能没有,所以叫可选的 1:1。如果把直播拆成单独的表,请柬一端画两条竖线,直播一端画圆圈和竖线。
不过课程说其实没必要这样做。在请柬表上加一个链接列,只给申请的人填上就行。这个值最多只有一个,按前面的标准就是列。
需要拆出来的情况,是这个格子空着的次数太多。如果十对新人里只有一对申请,其余九行的这一格都是空的。课程解释说,空格这么多、想管理得更有效率时,也可以拆成 1:1。不过这不是主流用法。1:1 只当作一个选项记住,默认还是列。
[默认] invitations 表加一列
id title live_stream_url
1 我们结婚了 (空)
2 春日之约 https://live.example.com/abc
[可选] 单独的 live_streams 表
id invitation_id url
1 2 https://live.example.com/abc原本是 enum 的模板变成表的那一刻
最初的设计里,模板定为 1、2、3 三种。这种只接受事先定好的值、其他值一进来就报错的数据类型叫 enum。这和把登录方式限定为 Kakao、Google、Apple 是同一种做法。
可是模板设计不够好,于是新招了设计师,想不断增加模板。一开始是改代码加上 4 号,再加 5 号,再去掉 1 号。这种事一再发生,每次都要动代码或数据库就变得很麻烦。
这时干脆把模板做成一张表。每个模板有自己的 id(使用 UUID,一种为了不重复而生成的 ID 字符串),请柬不再用 enum 列,而是有一列 template_id。template_id 指向模板表的 id。一个模板可以做出多张请柬,所以模板和请柬是 1:N,模板是父。
课程留下的启示是:即使是定成几个值的东西,以后一旦需要管理,也可以从列拆成表。如果增删变得频繁,那个值就不再是属性,而是成了管理对象。不过,把已经存下的请柬上的 1、2、3 迁移到新 id 的工作需要小心,这会在第 04 篇讲。
今天可以做的事:让 AI 整理出当前项目的表结构,再用下面的请求逐项检查。下一篇看多位管理员共同管理一张请柬的多对多关系如何用中间表来解决,以及如何用 Mermaid(把写成代码的文字变成图的工具)让 AI 画出 ERD。
[之前] invitations — template 是 enum
id title template
1 我们结婚了 template_1
2 春日之约 template_2
[之后] templates 表 + template_id
templates
id name
t-01 经典
t-02 花卉
invitations
id title template_id
1 我们结婚了 t-01
2 春日之约 t-02把这个项目的数据库表和列整理成表格。
然后找出下面三类:
1. 把可能有多个的值塞进一列的地方
(例如 greeting1、greeting2 这种带编号的列,或用逗号连在一起的值)
2. 大多数行都为空的列
3. 事先定好的值(enum)中,今后管理员需要增删的
逐一告诉我应该拆成表还是可以保留为列,并说明理由。
先不要改任何东西。