第一范式(First Normal Form, 1NF)是数据库规范化的起点阶段,它对表结构有严格的限制。表满足1NF时:
- 所有数据都是原子的。表格里的每个单元格都只能有一个不可再分的值。再见了,“一个单元格里放列表”!数据库里绝对不能这么干。
- 每一行都是唯一的。也就是说,表里得有主键(Primary Key)或者唯一标识符。
- 没有重复的数据组。同一个实体的值不能出现在同一列里。
简单说,想象一下数据库表就是你的房间,原子值就是独立的物品:灯、桌子、书。如果房间乱成一团(比如所有东西都堆一起),你根本找不到灯,也不知道有没有备用桌子。规范化就是帮你“把一切都分门别类放好”。
1NF违规的例子
假设我们有一张学生表,记录他们上的课程:
| student_id | name | courses |
|---|---|---|
| 1 | Maria | "数学, 物理" |
| 2 | Rob | "生物, 化学" |
这个结构哪里不好?课程(courses列)是用逗号分隔写在一个单元格里的。如果你想查找所有学物理的学生,SQL查询会变得很麻烦:得做一堆字符串处理。如果有学生想把物理从列表里删掉,又是一堆新问题。这种数据不是原子的,直接违反了1NF的核心规则。
怎么让表满足1NF?
要解决这个问题,我们把数据拆成多行,每个单元格只放一个原子值:
| student_id | name | course |
|---|---|---|
| 1 | Maria | 数学 |
| 1 | Maria | 物理 |
| 2 | Rob | 生物 |
| 2 | Rob | 化学 |
现在就没问题了。我们把表变成了每个单元格都是不可再分的值。这样就符合1NF的原则了。
详细的1NF违规和修正例子
假如我们有一个网店订单表:
| order_id | customer_name | items |
|---|---|---|
| 1001 | Otto Lin | "笔记本, 鼠标, 键盘" |
| 1002 | Anna Song | "智能手机, 手机壳" |
很明显,items里用逗号分隔了多个值,这就违反了1NF。
要让数据满足1NF,我们把每个商品都单独存一行:
| order_id | customer_name | item |
|---|---|---|
| 1001 | Otto Lin | 笔记本 |
| 1001 | Otto Lin | 鼠标 |
| 1001 | Otto Lin | 键盘 |
| 1002 | Anna Song | 智能手机 |
| 1002 | Anna Song | 手机壳 |
现在表结构就符合1NF了。每个订单和商品都是独立的一行,值都是原子的。
添加主键
表转换后,记得加上唯一标识符(主键),保证每行都是唯一的。上面例子里可以用order_id和item的组合做复合主键。但实际开发中一般会单独加个id字段。
| id | order_id | customer_name | item |
|---|---|---|---|
| 1 | 1001 | Otto Lin | 笔记本 |
| 2 | 1001 | Otto Lin | 鼠标 |
| 3 | 1001 | Otto Lin | 键盘 |
| 4 | 1002 | Anna Song | 智能手机 |
| 5 | 1002 | Anna Song | 手机壳 |
实践任务
你有一张学生表,科目都写在一个单元格里:
| student_id | name | subjects |
|---|---|---|
| 1 | Polly | "数学, 化学" |
| 2 | Peter | "物理, 信息学" |
把表转换成1NF的形式。
转换后表应该长这样:
| student_id | name | subject |
|---|---|---|
| 1 | Polly | 数学 |
| 1 | Polly | 化学 |
| 2 | Peter | 物理 |
| 2 | Peter | 信息学 |
1NF常见错误
你在用数据库时,1NF违规经常出现在这些场景:
- 直接在表里存列表或数组。这是最常见的坑。
- 没有给行加唯一标识(主键)。这样表很容易出现重复数据。
- 用多个列存同样的信息。比如“course_1”,“course_2”,“course_3”——其实应该用更规范的结构。
记住这些点,你的数据库就能符合第一范式。
1NF的实际应用
在真实项目里,1NF特别重要。比如:
- 在客户管理(CRM)应用里,客户和他们的操作数据都得是原子的,这样分析和查找才方便。
- 在网店里,1NF用来高效存储订单、商品和买家信息。
- 在银行系统里,客户、账户和交易的数据必须原子化,才能避免不同操作混淆。
遵守1NF原则能让数据库抗高并发,还好用。虽然这样会有点数据重复,但没关系。接下来我们会讲第二范式(2NF),到时候你就知道怎么处理表里的部分依赖了。
为什么要遵守第一范式(1NF)?想象一下你在表里存数据,一个单元格里能有好几个值——比如买家下单的商品列表。这样查数据就很难:比如想找所有买了“键盘”的人,简直要疯。如果要改或删一部分信息,也很容易出错。数据原子化——也就是每个字段只存一个值——让操作更安全、更清晰。而且,这样的表更容易扩展、更新和重构。
GO TO FULL VERSION