数据库三大范式通俗解读:用实例讲清 “为什么不能乱建表”

数据库三大范式通俗解读:用实例讲清“为什么不能乱建表”

场景设定:学生选课系统

假设我们设计一张表存储所有数据:

CREATE TABLE 学生选课 (
    学号 INT,
    姓名 VARCHAR(20),
    系名 VARCHAR(20),
    系主任 VARCHAR(20),
    课程号 INT,
    课程名 VARCHAR(20),
    成绩 INT
);

数据示例:

学号姓名系名系主任课程号课程名成绩
101张三计算机王老师301数据库90
101张三计算机王老师302算法85
102李四数学刘老师302算法95

第一范式(1NF):原子性

要求:每列不可再分,消除重复组

问题:如果“课程”字段存储多值(如 "数据库,算法"),会导致查询困难。

解决:确保每列只存单一值(已满足)。

违反后果

  • 无法直接查询“张三的数据库成绩”
  • 统计成绩需拆分字符串,效率低下

第二范式(2NF):完全依赖

要求:非主属性必须完全依赖于主键(消除部分依赖)

主键(学号, 课程号)(联合主键)

问题

  • 姓名、系名只依赖学号(部分依赖)
  • 课程名只依赖课程号(部分依赖)

数据冗余

  • 张三的系名重复存储(计算机系出现2次)
  • 算法课程名重复存储(出现2次)

解决:拆表消除部分依赖

-- 学生表(主键:学号)
CREATE TABLE 学生 (
    学号 INT PRIMARY KEY,
    姓名 VARCHAR(20),
    系名 VARCHAR(20)
);

-- 课程表(主键:课程号)
CREATE TABLE 课程 (
    课程号 INT PRIMARY KEY,
    课程名 VARCHAR(20)
);

-- 选课表(主键:(学号,课程号))
CREATE TABLE 选课 (
    学号 INT,
    课程号 INT,
    成绩 INT,
    PRIMARY KEY (学号, 课程号)
);


第三范式(3NF):消除传递依赖

要求:非主属性不能依赖其他非主属性

问题:在学生表中:

  • 系主任依赖系名(传递依赖)
  • 若计算机系更换主任,需修改所有该系学生的记录

数据异常

  • 更新异常:修改一个系的主任,需更新多条记录
  • 插入异常:新成立中文系(尚无学生),无法存入系主任
  • 删除异常:删除所有数学系学生,系主任信息丢失

解决:拆表消除传递依赖

-- 学生表(主键:学号)
CREATE TABLE 学生 (
    学号 INT PRIMARY KEY,
    姓名 VARCHAR(20),
    系名 VARCHAR(20)  -- 只存系名
);

-- 院系表(主键:系名)
CREATE TABLE 院系 (
    系名 VARCHAR(20) PRIMARY KEY,
    系主任 VARCHAR(20)
);


最终设计(符合3NF)

表名字段主键
学生学号, 姓名, 系名学号
院系系名, 系主任系名
课程课程号, 课程名课程号
选课学号, 课程号, 成绩(学号, 课程号)

优势

  1. 零冗余:系主任只存1次(无论多少学生)
  2. 更新安全:修改系主任只需改1条记录
  3. 删除安全:删除学生不影响院系信息
  4. 插入灵活:可单独添加院系(无学生时)

核心结论:乱建表会导致数据冗余、操作异常和维护灾难。三大范式通过拆分表,用空间换稳定性,是高效数据库设计的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值