拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

医院门诊管理系统数据库设计:从数据流程图到关系模式规范化的完整链路

医院门诊管理系统数据库设计:从数据流程图到关系模式规范化的完整链路

简介:面向数据库课程设计作业或医院信息系统入门开发的读者,这份《医院门诊管理系统数据库设计课程设计》doc文档提供了较为完整的设计参考。内容以实际门诊业务流程为背景,覆盖挂号、收费、诊断、取药和治疗等一体化管理需求,在数据库设计层面依次展开需求分析、概念结构设计、逻辑结构设计、物理设计以及实施与测试等环节。概念设计中包含分ER图与全局ER图的建立,逻辑设计中重点说明了关系模式建立、规范化处理、用户子模式定义和逻辑结构定义,有助于理解如何消除数据冗余并避免更新异常。包体为1个doc文件,大小约1.5MB,虽然文件数不多,但结构紧凑,适合对照撰写课程设计报告或进行答辩思路整理。目前已有78人学习下载;对想快速掌握医院门诊管理系统数据库建模要点、并借鉴文档排版与设计流程的读者来说,有较强的参考价值。

1. 医院门诊管理系统数据库设计:一份能当模板照着走的完整设计链路

医院门诊管理系统数据库设计,几乎是软件工程专业课程设计的标配题目。我帮人改过不少这类作业,发现大多数人不是写不出来,而是被前面那一大堆设计文档卡住——需求分析写了两页纸就没了,数据流程图画了一张就开始编表,数据字典更是直接缺席。这份文档不一样,它是从三层数据流程图、五部分数据字典、分E-R图和全局E-R图、关系模式规范化一路走下来的,每一步都有东西可查、可抄、可改成自己的。适合正在写数据库课程设计论文的人复现流程,也适合第一次独立做数据库设计的人拿它当参照系,看看一套完整的门诊管理系统数据库到底该怎么拆。

2. 需求分析:63个数据项和27条数据流是怎么从门诊流程抽出来的

需求分析是整份文档的地基。文档在这里做了两件事:一是用数据流程图把门诊业务画清楚,二是用数据字典把流程里的每个数据细节固定下来。很多课程设计在这步偷懒,直接跳到建表,结果后面E-R图画不出来、关系模式对不上。这份文档把流程图画到了第三层,数据字典五件套齐全,规模是63个数据项、19个数据结构、27条数据流、10个处理逻辑、10个数据存储,够扎实。

2.1 三层数据流程图:先画业务再落数据

数据流程图的核心思路是“从业务到数据”,不是从字段反推流程。文档分了底层、第一层、第二层三个层次。底层只有两个对象——病人和医院门诊管理系统,从宏观上描述“病人走进医院、系统处理完、病人走出去”的完整闭环。第一层把系统拆成三个子系统:挂号收费、诊断、取药治疗,对应文档里的P1、P2、P3。第二层再把每个子系统往下拆,比如挂号收费拆成挂号、收费、分配医师,诊断拆成初诊、辅助检查、确诊或需转院,取药治疗拆成确定治疗方案、取药、治疗。

我一般会提醒别人:画数据流程图时不要一上来就想着数据库表。先完全站在业务视角,把病人从挂号到拿药走一遍,每一站就是一条数据流。文档里第二层数据流程图分成了三张图来画,这个习惯比硬塞在一张图里好维护得多。分层的好处是每一层只回答一个问题:顶层回答“和系统打交道的人是谁”,第一层回答“系统里有哪些业务域”,第二层回答“每个业务域内部有几步操作”。

提示:判断流程图画得够不够细,就看能不能从图里直接数出“处理逻辑”。文档第二层拆出来的P1.1到P3.3,就是后面数据字典里10个处理逻辑的来源。图和数据字典是互相印证的,不是各写各的。

2.2 第二层数据流程图:挂号收费、诊断、取药治疗怎么再拆分

第二层三张图分别对应三个业务的内部数据流动。挂号收费部分可以看到四个处理框:挂号、收费、分配医师、修改值班医生信息。这里面有个容易被忽略的点——分配医师。挂号处挂了号之后,得有人根据挂号信息和值班医生记录把医生分给病人,这个动作在流程图里是独立的一条处理逻辑,不是挂在挂号下面的附属品。

诊断部分拆成初诊、辅助检查、确诊或需转院三个处理框。初诊产生初诊信息,需要辅助检查的就产生检查报告,确诊之后进入确诊或需转院流程。注意这里有个关键分支:确诊不需要转院的,走处方和病例;需要转院的,走转院报告。转院这个动作在很多简化版的门诊系统里是没有的,文档里把它单列出来,说明需求分析阶段考虑得比较全。

取药治疗部分拆成确定治疗方案、取药、治疗三个处理框。这里面比较有价值的是治疗和收费的联动——治疗会产生治疗费信息,这些信息流到收费记录里,说明治疗不是免费的。不少人在这个环节会漏掉治疗收费,导致收费单和挂号费、药费都对不上。

2.3 数据字典五件套:数据项、数据结构、数据流、处理逻辑、数据存储

数据字典是本轮最实打实的部分。它包含五个组成部分:数据项、数据结构、数据流、处理逻辑、数据存储。数据项是原子字段,共63个,是数据结构的最小单位。数据结构是将相关数据项组合成业务对象,共19个,比如医师、挂号单、收费单、处方、诊断书、病人、初诊报告、转院报告等。数据流描述数据在系统里的流动,共27条,每条都标明来源、去向、组成。处理逻辑是对每个业务步骤的解释,共10个,每个都标了输入数据流、输出数据流和处理频率。数据存储是保存下来的数据集合,共10个,对应挂号记录、收费记录、诊断记录、药物记录、治疗记录等。

数据字典组成数量说明
数据项63病人、医生、药品、收费、诊断各环节的字段
数据结构19医师、挂号单、收费单、处方、诊断书等
数据流27挂号请求、缴费、处方、药物信息等流转
处理逻辑10挂号、收费、初诊、辅助检查、取药、治疗等
数据存储10挂号记录、收费记录、药物记录、治疗记录等

数据项的编号也值得学一下:DI-01到DI-63,每个编号后面都标注中文含义、类型和长度。比如DI-50 Mno是药物编号,主键,varchar(20)。这样一份数据字典,写论文的时候可以直接往附录里放,答辩的时候老师问任何一个字段,都能在字典里找到它的位置和约束。血泪经验是:很多课程设计的数据字典只有字段列表,没有来源和去向信息,导致后面关系模式设计时外键全靠猜。这份文档的数据流是带方向的,谁发给谁、由谁处理都标清了,照着画E-R图就不会错。

3. 概念设计:三张分E-R图合成全局E-R图时的取舍

概念设计阶段的目标是把需求分析里的数据字典和数据流程图抽象成E-R图。文档采用了“先分后总”的套路:先为挂号收费、诊断、取药治疗三个子系统分别画分E-R图,然后合并成一张全局E-R图。合并的过程是这道工序的难点,因为三个分图里有大量重复实体和不同名的同类属性,处理不好就会造成冗余和冲突。

3.1 三个分模块的实体识别:病人、医生、科室、处方、治疗记录

挂号收费分E-R图里,实体有病人、挂号单、收费单、医生、值班医师记录、收费标准。这里面有一个细节值得学习:收费标准和收费单被建成了两个实体,收费标准是字典表,保存价目,收费单是业务表,记录一次具体的收费行为。这两个分开,后面收费调整时不需要改动历史单据。很多初学者把收费标准里的价格直接塞进收费单,导致改价后历史数据全乱。

诊断分E-R图里,实体有病人、诊断记录、初诊信息、检查报告、医师、科室。看看这个实体清单,能发现一个常见的误区——初诊信息、检查报告、确诊结果其实是三个不同的实体,不能合并成一张诊断表。文档里把它们拆开,因为初诊、辅助检查、确诊在时间上有先后,在数据流上也是分步产生的。

取药治疗分E-R图里,实体有医生、处方、药物记录、治疗方案、治疗记录、病人。这里面处方和药物记录是两类实体,处方是一次开药的业务行为,药物记录是药品的库存和价格信息,通过处方内容产生联系。

3.2 全局E-R图合并:消除命名冲突与结构冲突

全局E-R图的合并重点在于处理三类冲突。第一是命名冲突:同一个实体在不同分图里可能叫不同的名字,需要统一。比如诊断分图里叫“医师”,挂号收费分图里叫“医生”,合并时统一叫医生。第二是结构冲突:同一个实体在不同分图里属性不完全一致,需要取并集。比如病人在挂号收费分图里有姓名、证件号,在诊断分图里有性别、年龄,合并后就是完整的病人实体。第三是冗余冲突:同一联系在多张分图里重复描述,保留一个语义最完整的即可。

文档强调了合并时“将相同的实体合并,属性近似的实体合并成一个,尽量减少冗余”。这句话听着像套话,实际操作时盯住一个标准:任何一个实体都不能重复出现在最终E-R图里,任何一个联系的语义都不能有歧义。拿病人在三张分图里出现三次来说,合并完就一个病人实体,出图的业务边界由它关联的挂号单、诊断记录、治疗记录来决定。

3.3 联系的属性与基数比:1:1、1:n、m:n怎么判

E-R图上实体之间的联系必须有明确的基数比,这是后面转关系模式的依据。文档里的几个典型联系值得分析:病人和挂号单是1:1,一个病人一次挂号只产生一张挂号单;挂号单和收费单也是1:1,一次挂号对应一次门诊收费;医生和科室是m:1,一个科室有多名医生,一名医生属于一个科室;医生和处方是1:n,一个医生可以开多张处方;处方和药物是m:n,一张处方包含多种药物,一种药物也可以出现在多张处方里。

判断基数的通用方法是各问一遍“一方的记录能否对应多方的多条记录”。比如判断医生和处方:一个医生能否开多张处方?能。一张处方能否被多个医生开?不能。所以是1:n。这个方法看着简单,但能解决大多数实体关系的判定。我见过不少人把处方和药物做成1:n,结果一张处方只能存一种药,药房对处方的时候就崩了。

E-R图的难点在于把数据字典里的数据结构映射成实体,同时把数据流里的处理逻辑映射成联系。文档里提到了“各种票据可以声明为实体也可以声明为联系”,这句是给ELOOK图建模的一个实操提示——如果一张票据在后续关联里需要被单独统计,就建实体;如果只是记录一次交互,就建联系。收费单建实体,是因为后面要统计收入。

4. 逻辑设计:E-R图转关系模式与规范化处理的检查路径

逻辑设计是把E-R图翻译成关系模式的过程。文档在这一步做了三件事:建立关系模式、关系模式规范化、建立用户子模式。这个顺序不能乱,先有模式,再检查范式,最后按角色建视图。很多人在这一步的问题是想一步到位,直接从E-R图跳到建表SQL,中间跳掉了规范化检查,结果表建出来运行时才发现更新异常。

4.1 E-R图转关系模式的四条规则

E-R图转关系模式有固定规则。实体直接转表,实体的属性转字段,主键保留。1:1联系可以并入任一端实体的表里,另一端的主键作为外键放进来。1:n联系在n端实体的表里增加一列,存放1端实体的主键。m:n联系需要单独建一张中间表,中间表的主键是两端实体的主键组合,也可以再加一个自增主键。

按这个规则,文档里的几个典型转换会是这样的:病人和挂号单是1:1,可以把挂号单主键并入病人表,也可以反过来,实际设计中更推荐在挂号单表里放病人编号,因为挂号单的查询频次远高于病人表。科室和医生是1:n,医生表里放科室编号作为外键。医生和处方是1:n,处方表里放医生编号。处方和药物是m:n,单独建一张处方明细表,存处方编号、药物编号、数量、价格。

提示:m:n关系必须建中间表,这是最容易被跳过的规则。处方和药物如果不建明细表,直接在处方表里放一个“药物编号”字段,一个处方多药时就得拆成多行,处方主键也不唯一了。

4.2 规范化处理:从1NF到3NF的检查路径

规范化处理的目的是消除数据冗余和更新异常。课程设计做到3NF就足够,文档里没有提BCNF和4NF,说明作者很清楚边界。检查路径分三步:第一步检查有没有重复组,确保每个字段都是原子值,这是1NF;第二步检查主键是否为单列,如果主键是复合键,就检查非主属性是否对主键的全部依赖,存在部分依赖就拆表,这是2NF;第三步检查非主属性之间是否有传递依赖,存在就拆表,这是3NF。

拿门诊场景举个例子。假设挂号单表里有挂号编号、病人编号、病人姓名、医生编号、医生姓名、科室编号。这里挂号编号是主键,病人姓名依赖病人编号而不是挂号编号,医生姓名依赖医生编号而不是挂号编号,这是典型的传递依赖。正确做法是拆成挂号单表存病人编号和医生编号,病人姓名查病人表得到,医生姓名查医生表得到。文档里数据结构独立成Doctor、Patient、Register,本身就避开了这个问题。

4.3 用户子模式:不同角色看到不同的视图

用户子模式是为不同角色设计的视图。挂号处的人不需要看到诊断结果和处方明细,医生不需要看到收费标准,药房的人需要看库存但不需要看病人病史。文档里把收费单、处方、诊断书等都设计成了独立的数据结构,为建视图提供了基础。

常见做法是在逻辑设计阶段就预留视图接口,后面物理设计时直接按角色建视图。比如挂号处视图只关联病人表、挂号单表、收费单表;医生视图关联诊断记录、初诊报告、辅助检查报告;药房视图关联处方表、药物记录表。视图的存在让不同角色面对的是“自己的表”,而不是整库的完整结构。这个设计对应用层开发很友好,写业务代码时不用每次join多张表。

5. 实施与测试避坑:建表、入库顺序和四个翻车现场

实施阶段是把逻辑设计变成物理表、把数据装进去、把测试跑通的过程。文档在实施部分列了“数据库及数据库对象建立”“数据入库”“数据库测试”三个步骤。这一步看着像体力活,其实坑最多。我按自己的实践经验把这部分拆细一点,先说建表和入库的顺序,再说几条高频踩坑记录。

5.1 物理设计与建表落地

物理设计要决定字段类型、长度、约束和索引。文档的数据字典里大量字段是varchar(20),这个长度对编号、姓名、科室名都够用,不要想都不想就改成text,text字段没法直接建索引,后面按病人编号查历史记录时会非常难受。金额字段用decimal而不是float,门诊收费涉及金额计算,float的精度问题在累计统计时会翻车。时间字段用datetime,按“就诊时间”排序是高频操作。

建表顺序按依赖关系来:先建科室表、医生表、药物表、收费标准表这些基础表,再建挂号单、收费单、处方、诊断记录这些业务表。一个简化版的建表SQL示例:

CREATE TABLE doctor ( dno VARCHAR(20) PRIMARY KEY, dname VARCHAR(20) NOT NULL, ddept VARCHAR(20), office_no VARCHAR(20), FOREIGN KEY (office_no) REFERENCES office(eoffice_no) ); CREATE TABLE register ( rno VARCHAR(20) PRIMARY KEY, pno VARCHAR(20) NOT NULL, dno VARCHAR(20) NOT NULL, rtime DATETIME, FOREIGN KEY (pno) REFERENCES patient(pno), FOREIGN KEY (dno) REFERENCES doctor(dno) );

这段SQL里doctor表的外键指向office表,register表的外键指向patient和doctor,建表顺序必须是office先建、patient先建,否则外键引用不存在的表直接报错。我把register表的主键设计成独立的rno而不是用pno,是因为一个病人可能复诊多次,用pno做主键会限制一病人只有一条挂号记录。

5.2 数据入库顺序与测试用例设计

入库顺序和建表顺序一致,先基础表后业务表。先插科室和医生数据,再插病人数据,最后插挂号、诊断、处方。否则业务表里外键引用的基础数据还不存在,插入就会失败。课程设计通常数据量不大,手动插入几十条样例数据就够了,但要注意覆盖面:既要有正常完成的就诊记录,也要有一条走到转院的记录,还要有一条次日复诊的记录,这样后面跑查询测试时才能验证所有分支。

测试用例建议设计一个完整的业务场景:一个新病人到医院挂号,缴费,医生初诊,开辅助检查,出检查报告,确诊,开处方,药房取药,进入治疗,最后治疗结束。每一步执行一个对应的查询,确认数据正确写入。文档里的10个处理逻辑正好对应这个链路上的每个环节,逐个验证一遍,数据库设计的正确性基本就立住了。

5.3 避坑记录:四个常见的翻车现场

坑一:病人实体没有独立主键。现象是病人表用身份证号或手机号做主键,同一身份证号第二次挂号直接冲突,或者病人改手机号后历史记录全关联不上。原因是为了省一个字段,直接用业务字段当主键。解决方法是加一个病人编号pno作为自增或业务主键,身份证号只是普通属性,其他表统一引用pno。

坑二:挂号单和收费单合并成一张流水表。现象是缴费统计时数字对不上,已挂号的未缴费记录和已缴费记录混在一起,按时间统计时出现负数。原因是想减少表数量,把两个业务环节塞进一张表。解决方法是按文档拆成挂号记录和收费记录两张表,挂号单表加状态字段区分已缴费和未缴费,两个流程通过挂号单编号关联。

坑三:处方和药物直接做成1:n。现象是一张处方只能录入一种药物,开了三种药的处方要拆成三行,处方编号的完整性就没了。原因是设计时没意识到处方和药物是m:n关系。解决方法是建一张处方明细表,处方表只存处方编号、医生编号、病人编号和开方时间,每种药物的数量金额放到明细表里,这样一张处方对应多行明细,药物价格调整也不影响历史处方。

坑四:外键没有设定删除策略。现象是删除一个医生的记录时,关联的挂号单、处方、诊断记录报错或变成脏数据。原因是在物理设计阶段没考虑外键行为。解决方法是建表时显式声明ON DELETE策略,比如医生离职后他的历史处方单应保留,外键可以设SET NULL或RESTRICT,具体看业务是想保留历史还是禁止删除。

6. 验证技巧:三条SQL把门诊全流程跑出闭环

数据库设计完之后,不要急着写“设计完成”,先跑三条查询验证整个库能不能闭环。这三条SQL也是课程设计答辩时最容易被问到的“用一条SQL证明你的设计是对的”。

第一条,全流程追踪。给定一个病人编号,把挂号、诊断、处方、治疗四个环节的数据一次性拉出来,验证表间关联是否正确。

SELECT r.rno, r.rtime, d.dname AS doctor, dia.diag_result, p.pay_total, t.tschedule, t.tcycle FROM register r JOIN doctor d ON r.dno = d.dno LEFT JOIN diagnosis dia ON r.pno = dia.pno AND r.rno = dia.rno LEFT JOIN paybill p ON r.rno = p.rno LEFT JOIN treatment t ON r.rno = t.rno WHERE r.pno = 'P0001' ORDER BY r.rtime;

这条SQL的核心是LEFT JOIN而不是INNER JOIN,因为一个病人可能挂完号就离开,没有诊断和治疗记录,INNER JOIN会把这种场景过滤掉,验证就不全面了。

第二条,复诊查询。查同一个病人在某个时间段的多次就诊记录,验证系统能否支撑复诊场景。

SELECT pno, COUNT(*) AS visit_count, MIN(rtime) AS first_visit, MAX(rtime) AS latest_visit FROM register WHERE pno = 'P0001' GROUP BY pno;

能跑出这条结果,说明病人表的主键设计是正确的,挂号记录跟病人正确关联。

第三条,医生工作量统计。按科室和日期统计每个医生的接诊人数,验证多表聚合是否能正确工作。

SELECT o.ename AS office, d.dname AS doctor, DATE(r.rtime) AS work_date, COUNT(*) AS patient_count FROM register r JOIN doctor d ON r.dno = d.dno JOIN office o ON o.eoffice_no = d.office_no WHERE DATE(r.rtime) BETWEEN '2025-05-01' AND '2025-05-31' GROUP BY o.ename, d.dname, DATE(r.rtime);

那条统计SQL跑通,说明科室、医生、挂号单三张表的外键链路是通的,没有断链和冗余依赖。从那以后我每次做完数据库设计,都强制先跑这三条再交文档,全流程追踪验证关联、复诊查询验证主键、工作量统计验证聚合,哪条跑不出结果就回头改设计,直到闭环为止。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表