news 2026/4/26 10:32:34

别再死记硬背范式了!用这3个真实业务场景(选课/购物/医院),手把手带你搞定E-R图到3NF数据库设计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
别再死记硬背范式了!用这3个真实业务场景(选课/购物/医院),手把手带你搞定E-R图到3NF数据库设计

从业务场景实战出发:用3个案例彻底掌握E-R图与3NF设计

每次看到数据库教材里那些抽象的理论和符号,你是不是也感到头疼?E-R图、范式、实体关系...这些概念单独看都懂,但一到实际项目就无从下手。今天我们不谈枯燥的定义,直接通过选课系统医院管理系统超市购物系统这三个真实场景,带你一步步完成从需求分析到3NF设计的全过程。

1. 选课系统:多对多关系的经典案例

大学选课系统是理解数据库设计的绝佳起点。想象一下,每学期初学生们蜂拥而至抢课的场景——这个系统需要记录学生信息、课程详情以及谁选了哪门课。让我们拆解这个业务:

核心实体分析

  • 学生:学号(主键)、姓名、所属班级
  • 课程:课程编号(主键)、名称、学分
  • 班级:班级编号(主键)、专业名称

这里的关键在于识别"选课"这个行为产生的数据。成绩既不属于学生实体(因为同一学生不同课程成绩不同),也不属于课程实体(不同学生上同一门课成绩不同),它只存在于学生和课程发生关联时。

E-R图要点

  1. 学生与课程之间是多对多关系,需要用菱形表示"选课"联系
  2. "成绩"应作为联系属性而非实体属性
  3. 班级与学生是一对多关系(一个班级包含多个学生)
-- 最终3NF关系模型 CREATE TABLE 班级 ( 班级编号 CHAR(6) PRIMARY KEY, 专业名称 VARCHAR(50) NOT NULL ); CREATE TABLE 学生 ( 学号 CHAR(10) PRIMARY KEY, 姓名 VARCHAR(20) NOT NULL, 班级编号 CHAR(6), FOREIGN KEY (班级编号) REFERENCES 班级(班级编号) ); CREATE TABLE 课程 ( 课程编号 CHAR(8) PRIMARY KEY, 课程名称 VARCHAR(50) NOT NULL, 学分 TINYINT CHECK (学分 > 0) ); CREATE TABLE 选课 ( 学号 CHAR(10), 课程编号 CHAR(8), 成绩 DECIMAL(5,2), PRIMARY KEY (学号, 课程编号), FOREIGN KEY (学号) REFERENCES 学生(学号), FOREIGN KEY (课程编号) REFERENCES 课程(课程编号) );

注意:常见错误是把"学分"放在选课表中。实际上学分是课程的固有属性,与是否选课无关,必须放在课程表中避免冗余。

2. 医院管理系统:复杂业务关系的处理

医院场景比选课系统更复杂,涉及科室、医生、病房、病人等多维关系。我们先理清业务规则:

  • 一个科室有多个病房和医生
  • 一个医生只属于一个科室
  • 一个病房只属于一个科室
  • 一个病人有唯一主管医生
  • 一个医生可管理多个病人

设计过程中的关键决策点

  1. 科室电话归属问题

    • 错误做法:放在医生表中(导致数据冗余)
    • 正确做法:作为科室属性(符合3NF)
  2. 病房床位设计

    • 每张病床应有唯一标识(病房号+床位号组合键)
    • 病房与科室是一对多关系
  3. 医生与病人的关系

    • "主管医生"是病人实体的外键
    • 不需要单独的"诊治"联系表(因为是一对多关系)
-- 医院系统的3NF实现 CREATE TABLE 科室 ( 科名 VARCHAR(20) PRIMARY KEY, 科地址 VARCHAR(100), 科电话 VARCHAR(20) ); CREATE TABLE 病房 ( 病房号 VARCHAR(10), 床位号 VARCHAR(5), 科名 VARCHAR(20), PRIMARY KEY (病房号, 床位号), FOREIGN KEY (科名) REFERENCES 科室(科名) ); CREATE TABLE 医生 ( 工号 CHAR(8) PRIMARY KEY, 姓名 VARCHAR(20) NOT NULL, 职称 VARCHAR(10), 年龄 TINYINT, 科名 VARCHAR(20), FOREIGN KEY (科名) REFERENCES 科室(科名) ); CREATE TABLE 病人 ( 病历号 CHAR(12) PRIMARY KEY, 姓名 VARCHAR(20) NOT NULL, 性别 CHAR(1), 诊断 TEXT, 主管医生 CHAR(8), 病房号 VARCHAR(10), 床位号 VARCHAR(5), FOREIGN KEY (主管医生) REFERENCES 医生(工号), FOREIGN KEY (病房号, 床位号) REFERENCES 病房(病房号, 床位号) );

提示:在实际项目中,病房管理系统可能还需要考虑床位状态(空/满)、病人入院时间等扩展属性,这些都应该作为病人表的属性而非病房表的属性。

3. 超市购物系统:处理交易流水数据

超市收银小票看似简单,却包含了典型的交易场景所有要素:商品、收银员、交易流水、商品明细。分析业务特征:

  1. 一对多与多对多关系并存

    • 一个购物单对应多个商品(一对多)
    • 但商品也会出现在多个购物单中(多对多)
  2. 派生属性的处理

    • 小票上的"金额"是单价×数量计算得出
    • 总金额是所有商品金额的汇总

设计中的典型错误与修正

表1:常见错误设计 vs 正确方案

错误设计问题分析正确方案
把商品名称直接放在销售表中违反1NF(存在重复数据)商品名称只存在于商品表
在购物单表存储所有商品明细违反2NF(部分依赖)用单独的销售表记录每件商品
将总金额作为商品表的属性违反3NF(传递依赖)总金额应属于购物单或实时计算
-- 购物系统的3NF模型 CREATE TABLE 商品 ( 商品编号 CHAR(8) PRIMARY KEY, 商品名称 VARCHAR(50) NOT NULL, 单价 DECIMAL(10,2) CHECK (单价 > 0) ); CREATE TABLE 收银员 ( 工号 CHAR(6) PRIMARY KEY, 姓名 VARCHAR(20) NOT NULL ); CREATE TABLE 购物单 ( 单据编号 CHAR(14) PRIMARY KEY, 交易时间 DATETIME DEFAULT CURRENT_TIMESTAMP, 收银员工号 CHAR(6), 总金额 DECIMAL(12,2), FOREIGN KEY (收银员工号) REFERENCES 收银员(工号) ); CREATE TABLE 销售明细 ( 单据编号 CHAR(14), 商品编号 CHAR(8), 数量 SMALLINT CHECK (数量 > 0), 单价 DECIMAL(10,2), PRIMARY KEY (单据编号, 商品编号), FOREIGN KEY (单据编号) REFERENCES 购物单(单据编号), FOREIGN KEY (商品编号) REFERENCES 商品(商品编号) );

性能与规范的权衡

  • 虽然理论上总金额可以通过明细计算得出,但实际系统中通常会冗余存储(避免每次查询都要聚合计算)
  • 这种情况下需要建立触发器确保数据一致性:
CREATE TRIGGER 更新总金额 AFTER INSERT ON 销售明细 FOR EACH ROW UPDATE 购物单 SET 总金额 = ( SELECT SUM(单价*数量) FROM 销售明细 WHERE 单据编号 = NEW.单据编号 ) WHERE 单据编号 = NEW.单据编号;

4. 从E-R图到3NF的实战方法论

通过以上三个案例,我们可以总结出一套可复用的设计流程:

步骤一:业务需求分析

  1. 列出所有业务单据和报表
  2. 提取其中的数据项作为候选属性
  3. 识别明显的实体(名词)和关系(动词)

步骤二:绘制E-R图

  1. 用矩形表示实体
  2. 用菱形表示重要业务关系
  3. 确定基数约束(1:1、1:n、m:n)
  4. 将属性分配到最合适的实体或关系

步骤三:转换为关系模型

  1. 每个实体转为一张表
  2. 1:n关系通过外键实现
  3. m:n关系需要单独建表
  4. 检查所有属性是否都依赖于完整的主键

步骤四:规范化到3NF

  1. 消除重复组(达到1NF)
  2. 消除部分依赖(达到2NF)
  3. 消除传递依赖(达到3NF)
  4. 必要时进行反规范化(有明确理由)

表2:常见设计问题自查表

问题类型检查方法解决方案
违反1NF表中是否有重复列或多值字段?拆分为多行或多表
违反2NF非主属性是否依赖部分主键?拆分出新的实体
违反3NF非主属性是否依赖其他非主属性?移除传递依赖
冗余数据相同信息是否在多个地方存储?建立外键关联

最后记住,好的数据库设计不是一蹴而就的。在实际项目中,我通常会先画出初版E-R图,然后与业务人员确认关键关系,接着进行至少三轮的范式检查和调整。有时候适当的冗余(如订单总金额)反而能提升性能,关键是要有明确的理由和保障一致性的机制。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/26 10:32:33

别再混淆了!一文搞懂OpenCV中YUV_I420、NV12与BGR的转换与内存布局

深入解析OpenCV中YUV格式转换:从内存布局到实战应用 在视频处理与计算机视觉领域,YUV色彩编码系统因其高效的压缩特性而广泛应用。但许多开发者在实际使用OpenCV处理YUV格式时,常被I420、NV12等变种的内存排列规则困扰,更对cv::cv…

作者头像 李华
网站建设 2026/4/26 10:25:20

WindowResizer终极指南:如何强制调整任意窗口大小

WindowResizer终极指南:如何强制调整任意窗口大小 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 你是否曾经遇到过这样的情况:某些应用程序的窗口就像被胶…

作者头像 李华
网站建设 2026/4/26 10:19:33

3分钟搞定:Windows电脑一键安装iPhone USB网络共享驱动终极指南

3分钟搞定:Windows电脑一键安装iPhone USB网络共享驱动终极指南 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.c…

作者头像 李华
网站建设 2026/4/26 10:18:40

三月七小助手:崩坏星穹铁道全自动任务管理终极指南

三月七小助手:崩坏星穹铁道全自动任务管理终极指南 【免费下载链接】March7thAssistant 崩坏:星穹铁道全自动 三月七小助手 项目地址: https://gitcode.com/gh_mirrors/ma/March7thAssistant 你是否厌倦了每天在《崩坏:星穹铁道》中重…

作者头像 李华
网站建设 2026/4/26 10:17:34

霍格沃茨之遗DX12崩溃怎么解决?DXGI_DEVICE_REMOVED错误终极解决指南

屏幕突然卡死,随后弹出“DXGI_ERROR_DEVICE_REMOVED”错误,然后被强制退回桌面——这可能是《霍格沃茨之遗》玩家最头疼的瞬间。这个报错直译是“图形设备被移除”,通俗讲就是显卡驱动与系统或游戏“失联”了。作为同样在ws 11系统上使用中高…

作者头像 李华