☰
医院管理系统数据库设计:从业务流程到核心表结构的完整推导
2026/10/17 20:55:07 网站建设 项目流程

简介:这份医院管理系统数据库设计文档,面向计算机相关专业学生及数据库初学者,围绕HIS系统的核心需求,梳理了医院门诊、住院、药房、财务、检查等部门的业务流程与数据关系,适合用作课程设计、毕业设计或数据库原理课程的项目参考。压缩包内共1个docx文档,体积约398KB,内容完整、可直接阅读。文档从用户需求出发,详细介绍了组织机构、业务活动、实体关系建模、表结构转化、外键关联、索引优化以及数据冗余平衡等关键环节,并对数据完整性、一致性、安全性、系统性能与法规遵从性做了说明。目前已有173人学习下载,对于希望快速理解医院信息系统数据库设计思路、完成数据库建模作业或撰写设计文档的读者,具有较强的实用价值。

1. 医院管理系统数据库设计:一份能直接推导出 20 张核心表的完整需求文档

做数据库设计最怕的不是不会画 ER 图,而是拿到需求清单后不知道该拆成几张表、表之间怎么挂外键。这份医院管理系统数据库设计文档,把我见过的大多数课程设计文档最薄弱的环节补齐了:它把门诊和住院两条主线的业务流拆到了单据级,从挂号单、门诊病历、门诊处方到医嘱、手术、病案,每一类业务对象都给出了明确的数据结构和属性字段。顺着这份文档走一遍,你能推导出一套覆盖病人、医生、药品、检查、收费、病区的完整数据库模型,而不是只拿到一张空洞的总 E-R 图。

文档定位是数据库设计参考,不是上线代码。它适合正在做数据库课程设计、刚接触 HIS 系统、或者想把 ER 模型练扎实的人。我拆这份文档时最大的感受是:需求分析写得足够细,但数据字典部分有前后命名不一致的地方,恰恰是这些不一致,能帮你把设计规范补得更完整。

2. 业务模型先行:门诊与住院两条主线的流程拆解

2.1 门诊主线:从初诊登记到取药离院的单据链路

门诊业务流程在文档里描述得最完整。初诊病人到挂号处登记基本信息,包括姓名、年龄、住址、联系方式;复诊病人不会再次登记,直接挂号和就诊排号,由挂号处处理病历管理。这里有个容易被忽略的设计要点:挂号处承担了"建立病人档案"和"每次就诊排号"两件事,落到表设计上就应该拆成病人主表和挂号流水表,而不是把信息全塞进一张表。

病人缴完挂号费后持证明到相应科室就医,医生开出诊断结果、处方或检查申请单。这一步是整个门诊流程的分叉点:如果开的是处方,病人到收费处交费后去药房取药;如果开的是检查申请单,病人交费后到检查科室做检查,检查结果填入结果报告单再交回病人手中,病人再回原科室复诊。数据流图里把这步画得很清楚:检查科室要做检查记录,药房要记录药品出库,处方信息从门诊医生流向收费处再到药房。

药房的库存是这套流程里的隐含约束。当库存药品减少到一定量时,药房需要到药库办理药品申领,药库负责出库、入库和采购。也就是说,从门诊医生开处方到病人取药,中间其实经过了处方、缴费、发药记录、库存扣减、申领单五个环节。做表设计时,处方表、收费表、发药记录表、药品库存表、请领单表都需要独立存在,不能靠一张"药品流水"糊弄过去。

2.2 住院主线:医嘱如何驱动床位、检验、手术和发药

住院流程比门诊复杂的地方在于多了"病区"这个中间层。病人接到入院通知后到住院处办理手续,登记基本信息并交预交款或押金,然后由病区科室根据病人就诊的科室安排床位,录入缴费信息并维护。文档里特意提到病区科室要按照医生开出的医嘱执行,医嘱内容包括用药和检查申请,这两条分支分别触发不同的下游业务。

用药这条分支上,病区科室把医嘱中的用药分类综合统计,形成药品申领单,统一向药库领药,再按时按量发给住院病人,同时记录发药情况。检查这条分支上,病区科室把检查申请单发给检查科室,检查科室处理后将检查通知发回病区科室,由病区科室通知病人去做检查。这里能看出来住院用药和门诊取药的核心差异:门诊是病人自己拿着处方去交费取药,住院是病区汇总医嘱后统一申领,所以住院侧的药品消耗天然需要"申领单-发药记录-病人用药记录"三层结构。

手术流程的驱动关系也值得注意。病区科室提交手术申请给手术室,手术室安排手术日程、准备材料和器械,然后发出手术通知回病区科室,由病区科室通知病人进入手术室。手术室要记录麻醉记录、术中医嘱、材料器械使用情况。这意味着手术申请表、手术通知单、手术记录、麻醉记录都需要独立建模,且都要通过住院号或病人号与住院主记录关联,否则一台手术涉及多个病人时数据就乱了。

2.3 支撑系统运转的辅助部门与库存闭环

门诊和住院两条主线跑通后,还要看支撑部门之间的数据关系。药库负责药品贮存、发放和采购,药房负责根据处方生成领药单向药库领药,同时管理自身库存。文档里明确提到药库要处理药品申领单、管理出库入库,和对供应商的采购订单。财务科管医院所有财务业务,门诊收费处和住院处分别处理门诊和住院的费用环节,检查科室负责检查项目的执行和设备维护,病案室保存病人病案,手术室管理手术排程和器械耗材。

这些辅助部门的业务最终都会沉淀到三张核心表:药品相关表、收费相关表和病案相关表。药品供给侧有供应商表和订单表,药库有入库出库记录,药房有库存和发药记录;收费侧有收费项目表,挂号费、药品费、检查费作为三个独立金额字段存在;病案侧有病人入院科室、入院日期、入院诊断、出院日期、出院诊断这些关键字段。做系统边界划分时,文档明确说原始数据录入、数据更新和日常维护由人工完成,统计工作交给计算机完成,这就是信息系统和手动台账的分工边界。

3. 核心模块拆解:从数据字典到表结构的设计推导

3.1 十六个核心数据项的编码规约

文档给了一套完整的数据项清单,绝大多数主键采用 char(8) 定长编码:挂号号 Gh_no、病历号 Bl_no、处方号 Cf_no、检查序号 Jc_no、药品编号 kind_no、医生号 doctor_no、病人号 People_no、住院号 Zy_no、医嘱号 Yiz_no、药品请领号 B_no。唯一例外是订单号 Dd_no,类型长度是 char(20),原因是订单号需要承载供应商、订货批次等更多信息,8 位不够表达。

这套编码规约在实际建表时有明显的好处:所有主键都是定长字符串,索引效率比自增整数主键低,但可读性好得多,业务人员看到编号能直接判断出是哪类单据。缺点是命名风格没有统一,医生号有时叫 doctor_no,有时叫 Ys_no,供应商号同时出现了 Gys_no 和 Trader_no 两种写法。我拆文档时专门做了一张对照表,把这些别名对应的字段统一到一套命名规范下,否则后面写 JOIN 条件很容易翻车。

3.2 数据结构到表的映射:一张数据结构一张表

文档给出的 15 组数据结构基本可以直接映射成物理表。挂号单包含挂号号、挂号类别、主治医师、挂号人姓名、挂号科室、挂号日期;门诊病历包含病历号、病人姓名、主治医师、诊断时间、病历内容;门诊处方包含处方号、主治医师、病人姓名、病人性别、病人年龄、处方内容。这些结构里的"病人姓名"字段在表设计时要从病人表的主键派生,不能作为冗余字段直接存,否则病人改名或者录入错误时会产生数据不一致。

检查项目结构值得单独说一下,它包含检查序号、检查医师、检查时间、检查内容、检查分析、检查结果、检查收费。这段设计的亮点是把检查结果和检查收费放在同一张表里,好处是统计检查收入时不需要 JOIN 多张表;坏处是检查项目单价变化时需要靠冗余记录来保留历史价格。处理方案表包含处理方案号、医师号、开出时间、处理方案内容,其中医师号指向医生表,这就是典型的外键设计。

收费项目表是这套模型里最简练的一张:收费项目号、挂号费、药品费、检查费三个金额字段。实际场景里收费项目应该拆成收费明细表,但这份文档用单表承载三类费用的设计简化了课程设计复杂度,可以接受。

3.3 关系与外键:病人、医生、药品的关联路径

实体关系层面的设计要点集中在几个方向。病人与挂号单是 1 对 N 关系,一个病人可以产生多条挂号记录;病人与门诊病历是 1 对 N,复诊病人的病历应通过病人号关联,而不是通过挂号号关联。医生与处方是 1 对 N,一个医生可以开出多张处方;药库与药品是 1 对 N,一张药库库存记录对应一种药品。

数据流图里有一条容易忽略的路径:药品请领单由药房流向药库,药库再把药品出库给病区科室。这条路径在表设计上至少涉及请领单主表、请领明细表、出库记录表,而文档的数据字典只有请领单号 B_no 这个字段,没有展开明细。做二次开发时这部分要补,否则药房和药库之间对账没有数据支撑。

3.4 建表 SQL:核心表的 CREATE TABLE 示例

把上面的映射落到 MySQL,我给出核心表的建表语句,按这份文档的数据字典来写:

CREATE TABLE patient ( people_no CHAR(8) NOT NULL COMMENT '病人号,唯一编码', name VARCHAR(30) NOT NULL COMMENT '病人姓名', sex CHAR(1) NOT NULL COMMENT '性别:M/F', age INT(3) NOT NULL COMMENT '年龄', id_card CHAR(18) NOT NULL COMMENT '身份证号', birth_date DATE NOT NULL COMMENT '出生日期', address VARCHAR(100) DEFAULT NULL COMMENT '住址', phone VARCHAR(20) DEFAULT NULL COMMENT '联系方式', PRIMARY KEY (people_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='病人主表'; CREATE TABLE register ( gh_no CHAR(8) NOT NULL COMMENT '挂号号', gh_category CHAR(8) NOT NULL COMMENT '挂号类别', doctor_no CHAR(8) NOT NULL COMMENT '主治医师编号', patient_no CHAR(8) NOT NULL COMMENT '挂号人编号', dept_name VARCHAR(30) NOT NULL COMMENT '挂号科室', reg_date DATETIME NOT NULL COMMENT '挂号日期', PRIMARY KEY (gh_no), KEY idx_register_patient (patient_no), KEY idx_register_doctor (doctor_no) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门诊挂号单';

注意两处细节:病人主表的主键用 people_no,挂号单通过 patient_no 外键指向病人表,这样同一个病人多次挂号只会在 register 表产生多条记录,不会造成病人信息重复存储。挂号日期选用 DATETIME 而不是 DATE,因为一天之内可能有多轮挂号,只存到日期会丢失时间维度。索引方面,挂号单表要给 patient_no 和 doctor_no 建普通索引,因为这两列是高频查询条件。

4. 从文档到库:建库、初始化与统计查询落地

4.1 建库与字符集选择

建库第一步是把字符集定下来。医院系统的病人姓名、住址、诊断内容都会出现中文,如果建库时用了 latin1 或者 utf8,生僻字会在写入时报错或变成乱码。我一般会用 utf8mb4,它兼容 utf8 全部字符,还能处理生僻字和特殊符号,排序规则选 utf8mb4_general_ci 即可,查询性能比 utf8mb4_unicode_ci 略好,中文字段排序需求也不高。

CREATE DATABASE his_design DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;

建库时还要注意一个约定:表名尽量用业务英文名,不要用中文,字段注释写清楚中文含义。这份文档的数据字典字段名已经给了英文代码,比如 Gh_no、Bl_no,直接沿用到建表语句里保持可追溯性即可。

4.2 初始化基础字典表

建完核心业务表之后,需要先初始化一批基础数据。文档里反复出现科室、医生职称、收费项目、药库、供应商这五类基础信息,它们不是业务流水表,而是业务表的外键依赖。科室表至少要包含科室代码、科室名称、所属部门(门诊或住院)、负责人,医生职称可以简单用代码表存,收费项目表则要把挂号费、药品费、检查费三个费用项的当前标准值预置进去。

CREATE TABLE dept ( dept_code CHAR(8) NOT NULL COMMENT '科室代码', dept_name VARCHAR(50) NOT NULL COMMENT '科室名称', dept_type CHAR(4) NOT NULL COMMENT '所属部门:门诊/住院', leader VARCHAR(30) DEFAULT NULL COMMENT '科室负责人', PRIMARY KEY (dept_code) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='科室字典表'; INSERT INTO dept (dept_code, dept_name, dept_type) VALUES ('D001', '口腔科', '门诊'), ('D002', '内科', '门诊'), ('D003', '外科', '住院'), ('D004', '骨科', '住院');

有一种常见的做法是把收费项目直接做成一张"价目表",挂号费、检查费、药品费各是一行,带生效日期。这样会比文档里的收费项目表更灵活,因为药品价格会调整,只保留一个金额字段的话,历史对账根本拉不出来。如果想把这份文档升级成能长期用的库,这步建议直接做。

4.3 统计查询的代表性 SQL

业务能跑起来之后,真正常用的是三类统计查询:门诊收入汇总、药品库存预警、医生工作量统计。门诊收入可以从收费项目表直接聚合,因为挂号费、药品费、检查费三个字段都在同一行,一条 SUM 就能算出门诊的日收入:

SELECT DATE(reg_date) AS biz_date, SUM(gh_fee) AS total_gh_fee, SUM(yp_fee) AS total_yp_fee, SUM(jc_fee) AS total_jc_fee, SUM(gh_fee + yp_fee + jc_fee) AS total_income FROM register r JOIN charge_item c ON r.gh_no = c.sfxm_no WHERE reg_date >= '2024-06-01' GROUP BY DATE(reg_date) ORDER BY biz_date;

这段 SQL 的 GROUP BY 落在 DATE(reg_date) 上,如果数据量大要考虑加一个日期字段做冗余,否则每次统计都要对 datetime 做函数运算,索引会失效。药品库存预警可以用条件查询直接做,库存量低于阈值就输出到管理端提醒。医生工作量统计则以医生号为分组键,统计开处方数和涉及金额,支撑文档里提到的"根据统计数字完成工资计算"这个需求。

5. 避坑指南:医院数据库设计的高频踩坑记录

5.1 现象:病历号和挂号号被当成同一个东西用

拆这份文档之前,我见过好几个照着类似需求做出来的系统,复诊时把新挂号号直接当作病历号覆盖写入,结果同一个病人的历史病历被新记录顶掉,医生复诊时根本看不到以前的诊断内容。

原因在于挂号流程里挂号处同时承担了"登记病人基本资料"和"病历管理"两件事,而数据字典里挂号单和门诊病历是两个独立结构。挂号号标识的是"某一次就诊",病历号标识的是"这个病人的病历档案",一个病人可以有多条挂号记录,但病历档案只有一份。

解决方式是把病历号上升到病人主档层面,初诊登记时分配一次,之后所有复诊记录都通过病人号关联回同一份病历,而不是每次挂号都生成新的病历号。

5.2 现象:药房库存被并发扣成负数

模拟并发发药场景时,两个窗口同时给病人发同一种药品,执行 UPDATE 后库存变成了负数。文档里的药品表只有"数量"一个字段,完全没有并发控制,而药房发药恰恰是医院系统并发最高的操作之一。

原因是扣库存的 SQL 写成了先 SELECT 再 UPDATE,两条语句之间没有事务包裹,也没有条件约束。解决方式是把扣减写成原子操作,在一条 UPDATE 里完成判断和扣减。这也是为什么文档里要求"当药房库存的药品减少到一定量的时候,药房人员应到药库办理药品申领"——负数库存会把库存预警逻辑直接打穿。

START TRANSACTION; UPDATE drug SET quantity = quantity - 1 WHERE kind_no = 'K000001' AND quantity >= 1; COMMIT;

如果影响行数为 0,说明库存不足,事务需要回滚,不允许把负数写进去。更进一步的做法是建一张药品出入库流水表,每次发药先记流水再更新库存,对账的时候靠流水倒推库存,而不是直接信任库存字段。

5.3 现象:订单号用 8 位不够用

文档数据项里出现了两次供应商号,一次是 Gys_no,一次是 Trader_no,类型都是 char(8),但订单号 Dd_no 类型是 char(20)。这里其实暴露了一个常见问题:课程设计阶段的数据量预估是"每年 10000 张",char(8) 能容纳 1 亿个组合,看着够用,但订单号如果再夹带日期、供应商区域、采购类型这些信息,8 位很快就见底。

解决方式是直接把订单号设计成"业务前缀 + 日期 + 序列"的组合,比如 PO20240601-0001。这样订单号从编码上就能看出是采购订单,还天然支持按日期范围检索。供应商号也要统一命名,Gys_no 和 Trader_no 二选一,否则后续写关联查询时,同一个供应商得同时维护两个编号,极易踩坑。

5.4 现象:科室和手术室被设计成字符串字段

文档的手术数据结构里直接写了"手术室"作为组成字段,挂号单里有"挂号科室",医生表里有"所在医科",这些本来应该指向科室表或手术室表的字段全部做成了普通字符串。如果只是做展示,问题不大,但一旦要做跨科室统计、手术室排班、科室工作量核算,字符串字段就完全使不上力。

解决方式是把这类"场所/机构"概念全部实体化成表。科室表至少要有科室代码、科室名称、所属部门三个字段,手术室表要有手术室号、位置、当前状态、可用时段,然后业务表里只存代码外键。文档里没有给出这些表,但基于流程描述,这是最合理的补全方向。设备科、血库、后勤仓库同理,凡是后续要按"谁、在哪个场所、干了什么事"来统计的,都拆出来建表。

5.5 现象:医嘱和处方结构混用

文档的医嘱数据结构里写的是"诊断单序号、诊断类别、启动日期、处理日期、遗嘱内容",注意这里写的是"遗嘱",但从上下文看显然是医嘱。门诊处方和住院医嘱在业务上差异很大:门诊处方是病人自己拿着去交费取药,住院医嘱是病区汇总后统一申领药品,两者生成时间和执行路径完全不同。

如果建表时图省事把医嘱和处方合成一张表,就会出现同一个字段一会儿存门诊处方内容,一会儿存住院医嘱内容,类型长度和状态流转都对不上。解决方式是分成医嘱表、处方表两张表,通过统一的病人号关联到病人主档,各自维护独立的单据状态,这样门诊收费和住院记账也能各走各的流程。

6. 二次开发思路:把课程设计升级成可用的 HIS 子系统

6.1 用视图封装高频统计口径

这套设计跑起来之后,第一件值得做的事是把第 4 章的统计查询封装成视图。文档是给数据库课程设计用的,但实际二次开发时,应用层不会直接写复杂的 GROUP BY 和 JOIN,视图可以把口径固定下来:门诊日收入、住院日费用、医生工作量、药品库存预警。视图的最大价值不是性能,而是让多个开发人员写出来的统计结果一致,避免同一天收入两个版本。

6.2 补药品批次与效期管理

文档里药品表只设计了数量、单价、生产日期、保质期,但真实药房发药会遵循"近效期先出",同一药品不同批次的进价也可能不一样。我的做法是把药品表拆成药品档案表和药品批次库存表,药品档案表存通用信息,批次库存表存批次号、生产日期、有效期、批次数量。发药时从批次库存表按效期排序扣减,库存预警按批次维度触发。这一步做完,原来的单表库存模型升级成了进销存模型,也就有了和供应商订单对账的基础。

6.3 挂号与收费界面层的字段对齐

最后一步是把表结构和应用层界面做一次字段级对齐。挂号界面录入的是挂号类别、科室、医生、病人基本信息,收费界面录入的是收费项目、金额、支付方式。界面字段和表字段之间会有映射差异,我一般会画一张"界面字段到表字段"的对照表,逐个确认。最容易翻车的是日期时间格式和金额精度,界面传进来的是字符串,入库前必须统一转成 DATE、DATETIME 或 DECIMAL(10,2),否则排序和聚合结果全乱。

这套文档最值钱的地方是把业务流程拆到了单据级,我后来每次做管理系统设计,都强制自己先把业务里的每一种单据枚举出来,再开始建表。单据列清楚了,表结构基本就顺了。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询