数据库设计三范式(NF)之第一范式极简说明
一句话核心思想
第一范式就是:表中的每个字段都是不可再分的“原子”值。
换句话说,表中的每一列都应该只包含单一的值,而不能是值的集合、数组或者可以再拆分的复合值。
用一个生动的例子来解释
想象一下,我们要设计一张 订单表。
错误的设计(违反第一范式):
| 订单号 | 顾客姓名 | 商品 |
|---|---|---|
| 1001 | 张三 | iPhone, AirPods |
| 1002 | 李四 | iPad, Pencil |
这张表有什么问题?
-
商品列 包含了多个值(“iPhone, AirPods”)。这违反了1NF。 -
这会导致很多麻烦:
-
查询困难:很难写一个查询来找出所有包含了“AirPods”的订单。
-
更新困难:如果李四想把“Pencil”换成“Keyboard”,操作会很复杂,容易出错。
-
统计困难:无法简单地统计每个商品被卖出了多少次。
-
另一个常见的错误设计:
| 订单号 | 顾客姓名 | 联系方式 |
|---|---|---|
| 1001 | 张三 | 电话:13800138000 |
| 1002 | 李四 | 邮箱:lisi@email.com |
-
联系方式列 包含了类型和具体值两个信息,它可以被拆分成“联系类型”和“联系值”两列。这也违反了1NF。
如何改造?(使其符合第一范式)
核心操作:把复合值或多值拆分成“原子”值。
对于上面的 订单表,我们有几种符合1NF的设计方法:
方法一:使用多行表示(经典方法)
将多个商品拆分成多条独立的记录。
| 订单号 | 顾客姓名 | 商品 |
|---|---|---|
| 1001 | 张三 | iPhone |
| 1001 | 张三 | AirPods |
| 1002 | 李四 | iPad |
| 1002 | 李四 | Pencil |
现在,商品列的每一个单元格都只包含一个不可再分的值。它满足了第一范式。
方法二:拆分列(如果值是固定的、有限的)
如果商品数量固定(例如,一个订单最多只能买3件商品),可以拆分成多个列。(这种方法不常用,灵活性差)
| 订单号 | 顾客姓名 | 商品1 | 商品2 | 商品3 |
|---|---|---|---|---|
| 1001 | 张三 | iPhone | AirPods | NULL |
| 1002 | 李四 | iPad | Pencil | NULL |
这种方法虽然每个单元格都是原子值,但会产生很多空值(NULL),并且扩展性很差(如果规则变成最多买5件商品,就要改表结构),所以不是最佳实践。
对于 联系方式表,我们可以这样改:
| 订单号 | 顾客姓名 | 联系类型 | 联系值 |
|---|---|---|---|
| 1001 | 张三 | 电话 | 13800138000 |
| 1002 | 李四 | 邮箱 | lisi@email.com |
现在,每一列都是原子值。
为什么第一范式如此重要?
1NF是数据库设计的基石。没有它,后续的范式(2NF, 3NF, BCNF)都无从谈起。它确保了数据的基本结构是规整的,从而使得:
-
数据操作变得简单:可以使用标准的SQL语句(如
WHERE 商品 = 'AirPods')进行精确查询、更新和删除。 -
维护数据一致性:避免了在一个字段内修改部分数据带来的不一致风险。
-
为后续规范化打好基础:只有满足了1NF,我们才能清晰地分析字段之间的依赖关系,进而进行第二、第三范式的优化。
总结
第一范式(1NF)的要求非常简单粗暴:
-
每一列都是单一的、不可再分的数据项。
-
每一行和每一列的交汇点(单元格)有且只有一个值。
-
同一列中的所有值必须是同一数据类型。
你可以把它想象成Excel表格的最佳实践:一个单元格里只填一个内容,不要用逗号隔开一堆东西。 这是所有数据库设计的第一步,也是最基本的一步。

浙公网安备 33010602011771号