第三范式(3nf)要求消除传递依赖,即非主键字段必须直接由主键决定,而非通过其他非主键字段间接决定;例如学号→学院编号→学院电话即为典型传递依赖,需拆分学院信息至独立表。
识别传递依赖:先看字段之间“谁决定谁”
第三范式(3nf)的核心是消除传递依赖,不是画得漂亮就行。关键要判断:某个非主键字段,是不是通过另一个非主键字段间接被主键决定?
比如学生表里有 学号、学院编号、学院名称、学院电话——这里 学号 → 学院编号 → 学院电话 就是典型传递依赖。
- 别只盯着外键连线:Navicat 画了
学生.学院编号指向学院.学院编号,不代表自动消除了学院名称和学院电话的冗余 - 手动检查每个非主键字段:“它能不能仅靠主键唯一确定?还是得先知道另一个字段?”
- 常见陷阱:把“看起来有关联”的字段全塞进一张表,比如在订单表里直接存客户姓名、地址、联系电话——这些都该属于客户实体,不是订单的直接特征
拆表前先理清实体边界:每个表只描述一个“东西”
Navicat 的模型工作区(Model Workspace)不是画布,是建模工具。你拖进去的每个“实体”,必须对应现实世界中一个独立存在、有唯一标识的事物。
- 学生、课程、教师、学院、专业……这些是候选实体;但“学生所在学院的电话”不是实体,是学院的属性
- 一个实体只放它的**直接属性**:
学生表里可以有学号、姓名、出生日期;学院电话必须移到学院表里 - 多对多关系必须拆中间表:比如学生和课程,不能在学生表加
课程列表字段(违反 1NF),也不能在课程表加学生列表(同样不行),得建单独的选课表,含学号和课程编号两个外键
生成 SQL 前务必清理模型中的冗余字段
Navicat 的「正向工程」(Forward Engineering)会把你模型里画的所有字段原样转成 CREATE TABLE 语句——它不会帮你删掉那些本该被拆走的列。
- 常见错误:模型里
学生实体还留着学院名称字段,生成的 SQL 就真带这个列,导致后续插入/更新异常 - 正确动作:右键该字段 → 「删除字段」(不是隐藏、不是注释、不是改名)
- 生成 SQL 后,打开「SQL 预览」窗口,逐张表核对:
SELECT * FROM 学生返回的字段,是否每个都能回答“这个字段描述的是学生本身,而不是别的实体?” - 特别注意命名一致性:所有外键字段统一用
xxx_id(如college_id),避免混用college_name、dept_code等不一致命名,否则后续 JOIN 容易出错
验证是否真满足 3NF:不能只信界面连线
加了外键 ≠ 满足 3NF。最终得靠数据逻辑验证,不是靠 Navicat 是否允许保存模型。
- 执行查询:
SELECT DISTINCT 学院名称, 学院电话 FROM 学生,如果结果行数 >SELECT COUNT(DISTINCT 学院名称) FROM 学生,说明同一学院名称对应多个电话,违反 3NF - 更直接的办法:尝试在
学院表里修改一条学院电话,看是否只改一处就全局生效;如果还要同步更新几十条学生记录里的学院电话,说明没拆干净 - Navicat 不提供依赖分析或范式检查功能,也不会标红提示“此处存在传递依赖”——这步纯靠人工判断和 SQL 验证
范式是业务语义层面的约束,不是 Navicat 里拖几下线就能解决的。最容易被忽略的点在于:你画出来的模型,可能语法合法、外键完整、界面整洁,但只要字段归属错了一处,3NF 就不成立。











