ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

SQL Server 2008药店管理系统数据库课设:从E-R图到触发器完整拆解

SQL Server 2008药店管理系统数据库课设:从E-R图到触发器完整拆解

简介:这份数据库课程设计报告以药店管理系统为完整案例,面向高校计算机相关专业学生及需要完成数据库课设的学习者,帮助解决从需求分析到物理结构设计的全流程文档撰写问题。资源包内含1个doc文档,大小约353KB,内容按章节组织,涵盖系统简要说明、需求分析、概念结构设计、逻辑结构设计、物理结构设计等核心模块,并配有数据流图、数据字典、局部E-R图与综合E-R图等设计图表。报告以Microsoft SQL Server 2008为数据库平台,结合PowerDesigner与Diagram Designer完成模型设计,详细阐述了医生与药剂师信息管理、药品进货上柜与库存处理、处方与销售查询、用户权限管理及系统维护等功能的设计思路。目前已有673人学习下载,适合作为课设范文参考,也可用于理解规范化数据库设计的完整流程与文档结构。

1. 药店管理系统数据库课设:一份能直接跑通的 SQL Server 2008 报告拆解

如果你正在为数据库课程设计发愁,手里拿到的题目是“药店管理系统”,又不想从零开始画 E-R 图、写建表语句、调触发器,那这份《数据库课程设计报告-药店管理系统.doc》值得你花时间拆一遍。它不是那种只讲理论的八股文,而是把需求分析、概念设计、逻辑设计、物理设计到数据库实施整条链路都走完了,配套 SQL Server 2008 建库脚本、PowerDesigner 建模思路和 Diagram Designer 流程图。适合两类人:一是需要交课设、想找一份结构完整参考模板的在校生;二是刚接触 SQL Server,想拿一个业务闭环完整的小系统练手增删改查和触发器的初学者。我拿到这份文档后,第一反应是它的章节骨架很标准——需求、概念、逻辑、物理、实施五段式,但真正值钱的是第六部分那些能直接执行的 SQL 代码和触发器逻辑,下面按落地顺序拆开讲。

2. 需求到 E-R 图:把药店业务翻译成实体和联系

2.1 四类角色与六个功能模块的对应关系

这份报告在需求分析阶段把系统角色拆成医生、药剂师、客户、销售职工四种,功能模块列了基础数据处理、药品信息管理、营业数据处理、查询功能、用户权限管理、系统维护六项。很多人做课设时容易把角色和功能混在一起写,导致后面 E-R 图里实体和联系分不清。我的建议是先画一张角色-功能矩阵,把每个角色能操作哪些模块标出来,再决定哪些是实体、哪些是联系。

角色可操作模块对应实体/联系
医生开药、处方查询医生实体、开药联系
药剂师配药、药品库存查询药剂师实体、药品实体
销售职工出售商品、交接班结柜台职工实体、柜台实体
客户采购商品购买联系

这张表的作用是帮你确定 E-R 图里哪些该画成实体矩形、哪些该画成菱形联系。报告里把医生、药剂师、药品、柜台、柜台职工都列为独立实体,购买和开药作为联系处理,这个划分是合理的。如果你把“销售”也画成实体,后面逻辑设计时就会发现它没有独立主键,反而增加冗余。

2.2 局部 E-R 图到综合 E-R 图的合并技巧

报告里先画了药品、医生、药剂师、购买、柜台、柜台职工六张局部 E-R 图,再合并成综合 E-R 图。这个做法在课设里很常见,但合并时最容易翻车的地方是属性冲突和命名不一致。比如药品实体在局部图里叫“药名”,到了购买联系里可能写成“药品名称”,合并时如果不统一,后面建表就会多出冗余字段。

我一般会按这个顺序操作:先把每个局部图的实体名、属性名、主键列出来,用 Excel 做一张对照表;然后逐列检查同名不同义或同义不同名的情况;最后再画综合图。报告里药品实体的属性包括药品号、药名、库存、保质期、生产厂家、价格、销售总量、日销售量、周销售量、月销售量、季度销售量,主键是药品号。这里有个细节值得注意——销售总量和日/周/月/季度销售量放在药品表里,严格来说存在传递依赖,因为销售量应该由购买记录汇总得出。但课设层面为了查询方便这样设计也能接受,只是后面优化时要说明为什么不完全满足第三范式。

2.3 数据字典的字段定义与类型选择

报告的数据字典部分给出了柜台职工表、药品表、购买表、柜台表、医生表、药剂师表的字段清单。我把它整理成下面这张表,方便你直接对照建表:

表名字段类型说明
医生表name, age, sexchar(8)姓名为主键
药剂师表name, age, sexchar(8)姓名为主键
药品表medicineid, name, stock, period, jname, jiage, xiaoshouzongliang, rixiaoshouliang, zhouxiaoshouliang, yuexiaoshouliang, jiduxiaoshouliangchar(8)medicineid 为主键
柜台表counterid, ename, eid, counternamechar(8)counterid 为主键
柜台职工表eid, sex, age, ename, counterid, salchar(8)eid 为主键
购买表medicineid, buydatechar(8)联合主键

这里有个课设里高频出现的坑:所有字段都用 char(8),包括年龄、工资、价格这些数值型字段。这样做的好处是建表简单、不用考虑精度,坏处是后面做 SUM、AVG 聚合查询时 SQL Server 会隐式转换,数据量大时性能下降明显。如果你只是交课设,照抄没问题;如果想稍微规范一点,把 age 改成 int、jiage 和 sal 改成 decimal(10,2),查询会舒服很多。

3. 逻辑模型到建表脚本:从 E-R 图到可执行 SQL

3.1 关系模式转换与 BCNF 判定

报告在逻辑结构设计部分把 E-R 图转成了关系模式,并声称所有表都满足 BCNF。我逐条核对了一下,药品表的主键是药品号,非主属性包括药名、库存、保质期、生产厂家、价格、销售总量等,这些确实都完全函数依赖于药品号,没有部分依赖和传递依赖,满足 BCNF。柜台表、购买表、柜台职工表、药剂师表、医生表的情况类似。

但有一个地方报告写错了:购买表的关系模式写成“购买(药品号,药品日期)”,然后说“药品号—>药品日期”,这明显是把联合主键写成了单主键依赖。正确的应该是(药品号,药品日期)—>其他属性,且药品号和药品日期共同决定一条购买记录。你在写报告时如果照抄这句,答辩时可能被老师追问。建议改成“购买表的主键为(药品号,购买日期)联合主键,非主属性完全依赖于整个主键”。

3.2 建库建表脚本的逐段拆解

报告第六部分给出了完整的建表语句,我把它整理成可直接在 SQL Server 2008 里执行的版本,并补上注释:

-- 创建数据库(报告里没写,但实际执行前需要先建库) CREATE DATABASE PharmacyDB; GO USE PharmacyDB; GO -- 医生表 CREATE TABLE Yisheng ( name CHAR(8) NOT NULL PRIMARY KEY, age CHAR(8), sex CHAR(8) ); GO -- 药剂师表 CREATE TABLE yaojishi ( name CHAR(8) NOT NULL PRIMARY KEY, age CHAR(8), sex CHAR(8) ); GO -- 药品表 CREATE TABLE yaopin ( medicineid CHAR(8) NOT NULL PRIMARY KEY, name CHAR(8), stock CHAR(8), period CHAR(8), jname CHAR(8), jiage CHAR(8), xiaoshouzongliang CHAR(8), rixiaoshouliang CHAR(8), zhouxiaoshouliang CHAR(8), yuexiaoshouliang CHAR(8), jiduxiaoshouliang CHAR(8) ); GO -- 柜台表 CREATE TABLE guitai ( counterid CHAR(8) NOT NULL PRIMARY KEY, ename CHAR(8), eid CHAR(8), countername CHAR(8) ); GO -- 柜台职工表 CREATE TABLE guitaizhigong ( eid CHAR(8) NOT NULL PRIMARY KEY, sex CHAR(8), age CHAR(8), ename CHAR(8), counterid CHAR(8), sal CHAR(8) ); GO -- 购买表 CREATE TABLE buy ( medicineid CHAR(8) NOT NULL, buydate CHAR(8) NOT NULL, PRIMARY KEY (medicineid, buydate) ); GO

这段脚本里我做了两处调整:一是补上了 CREATE DATABASE 和 USE 语句,因为报告里只写了 use sql,实际执行时如果没建库会报错;二是给每张表显式声明了主键,报告原文里只有部分表带了 not null,没有 primary key 约束,后面建触发器时如果依赖主键会出问题。参数方面,char(8) 的长度对于姓名、药品名基本够用,但如果你要存中文药名超过四个字,建议改成 nvarchar(20) 或 nvarchar(50)。

3.3 触发器逻辑的修正与执行顺序

报告里在医生表、药剂师表、药品表上建了多个触发器,但代码有几处明显错误。比如医生表的删除触发器写成了for update,而且更新语句里用了未赋值的 @name_new。我按它的意图重写成可执行的版本:

-- 医生表更新触发器:同步更新相关记录中的医生姓名 CREATE TRIGGER t_Yisheng_Update ON Yisheng FOR UPDATE AS BEGIN IF UPDATE(name) BEGIN DECLARE @name_new CHAR(8), @name_old CHAR(8); SELECT @name_new = name FROM inserted; SELECT @name_old = name FROM deleted; -- 这里假设有其他表引用医生姓名,实际课设中可省略 -- 报告原文逻辑不完整,建议只保留 inserted/deleted 演示 END END GO -- 药品进货触发器:插入新药品时库存自动加一 CREATE TRIGGER j_yaopin_Insert ON yaopin FOR INSERT AS BEGIN DECLARE @newstock CHAR(8); SELECT @newstock = stock FROM inserted; UPDATE yaopin SET stock = stock + 1 WHERE medicineid = (SELECT medicineid FROM inserted); END GO

这里要说明的是,报告原文的药品进货触发器写的是update yaopin set stock=stock +1 where stock=(select stock from inserted),这个条件在有多条插入时会出错,而且 stock 是 char 类型,直接加 1 会隐式转换成 int 再转回来,如果 stock 里存的是非数字字符就会报错。我改成按 medicineid 匹配,更稳妥。执行顺序上,建议先建表、再插基础数据、最后建触发器,否则触发器可能因为表里没数据而无法验证。

4. 权限管理与查询语句:把课设跑成能演示的 Demo

4.1 用户权限分配的 GRANT 语句

报告在物理设计和实施部分都提到了用户权限管理,给出的语句是:

USE PharmacyDB; GO GRANT UPDATE(name) ON Yisheng TO guest; GO GRANT UPDATE(name) ON yaojishi TO guest; GO GRANT UPDATE(stock) ON yaopin TO guest; GO

这三条语句的意思是允许 guest 用户更新医生表、药剂师表的 name 字段,以及药品表的 stock 字段。课设演示时,你可以先用CREATE LOGIN guest WITH PASSWORD='Guest123'建一个登录名,再CREATE USER guest FOR LOGIN guest建数据库用户,然后执行上面的 GRANT。注意 SQL Server 2008 里 guest 默认是内置用户,如果你直接 GRANT 可能会提示用户已存在,建议换个名字比如pharmacy_guest。

4.2 销售查询与库存查询的 SQL 写法

报告里给了几条查询语句,我补全并加上注释:

-- 查询处方药品的名字、编号、价格 SELECT medicineid, name, jiage FROM yaopin; -- 查询药品销量:销售总量、日销量、周销量、月销量、季度销量 SELECT xiaoshouzongliang, rixiaoshouliang, zhouxiaoshouliang, yuexiaoshouliang, jiduxiaoshouliang FROM yaopin; -- 查询某柜台职工的销售业绩(假设通过购买表关联) SELECT g.eid, g.ename, COUNT(b.medicineid) AS 销售笔数 FROM guitaizhigong g JOIN guitai t ON g.counterid = t.counterid JOIN buy b ON t.counterid = b.medicineid -- 这里需要根据实际外键调整 GROUP BY g.eid, g.ename;

第三条查询里我故意留了一个问题:报告里没有明确购买表和柜台表之间的外键关系,所以t.counterid = b.medicineid这个连接条件是不成立的。实际课设中,你需要在购买表里加上柜台号字段,或者通过药品表间接关联。这也是答辩时老师容易问的点——你的表之间到底怎么关联的,有没有外键约束。建议在购买表里补一个counterid字段,并加上FOREIGN KEY (counterid) REFERENCES guitai(counterid)。

4.3 用 PowerDesigner 生成物理模型图

报告提到用 PowerDesigner 做概念模型和物理模型。如果你手头没有这个工具,可以用免费的 Diagram Designer 画 E-R 图,或者直接用 SQL Server Management Studio 的数据库关系图功能。操作步骤是:在 SSMS 里右键数据库 → 数据库关系图 → 新建 → 把六张表拖进去 → 手动建立外键连线。这样生成的图可以直接截图放进报告,比用 PowerDesigner 导出更省事。注意 SSMS 2008 的数据库关系图需要先安装 Microsoft Visual Studio 的某些组件,如果打不开,用 Dia 或 draw.io 替代也行。

5. 避坑与排查:课设里最容易翻车的五个地方

5.1 触发器递归导致“最大嵌套层数超出”

现象:执行更新医生姓名的语句后,SQL Server 报错“最大存储过程、函数、触发器或视图嵌套级别超出(限制为 32)”。原因:报告里的医生表更新触发器在触发后再次更新医生表,形成递归调用。解决:在触发器开头加IF TRIGGER_NESTLEVEL() > 1 RETURN;,或者改用INSTEAD OF触发器手动控制逻辑。更简单的办法是课设演示时只建一个方向的触发器,不要同时建更新和删除两个。

5.2 char 类型字段做数值运算结果异常

现象:药品库存 stock 字段存的是 '10',执行stock = stock + 1后期望得到 '11',实际却变成 '101' 或报转换错误。原因:char 类型在加法运算中先被转换成 int,但如果字段值包含空格或非数字字符,转换就会失败或截断。解决:建表时把 stock 定义为 int,或者在触发器里用CAST(stock AS INT) + 1再转回 char。课设报告里为了省事全用 char,实际跑的时候一定要在插入数据时保证 stock 字段只存数字。

5.3 外键缺失导致关联查询结果为空

现象:写了一个多表连接查询,结果返回零行,但每张表里明明都有数据。原因:表之间没有定义外键,连接条件写错了字段,或者字段值类型不匹配(比如一边是 char(8) 一边是 varchar(8))。解决:先用SELECT * FROM 表名确认每张表的数据,再单独执行连接条件看匹配行数。课设里建议至少给购买表的 medicineid 加上外键引用药品表,这样能保证数据一致性。

5.4 SQL Server 2008 安装后无法连接

现象:装完 SQL Server 2008 后,用 SSMS 连接报错“无法连接到服务器”,或者提示“SSL 提供程序证书链不受信任”。原因:SQL Server 服务没启动,或者 TCP/IP 协议没启用,或者加密证书配置有问题。解决:打开 SQL Server 配置管理器 → SQL Server 服务 → 启动 MSSQLSERVER;再点 SQL Server 网络配置 → 协议 → 启用 TCP/IP;最后在 SSMS 连接时勾选“信任服务器证书”。如果还是不行,把实例名改成localhost\SQLEXPRESS或.\SQLEXPRESS试试。

5.5 报告里 E-R 图和建表语句对不上

现象:答辩时老师指着 E-R 图问“这个联系对应的表在哪”,你发现建表脚本里少了一张关联表。原因:概念设计阶段画了 m:n 联系,逻辑设计时忘记转换成独立的关系模式。解决:对照 E-R 图逐个检查每个实体和联系,实体对应表,m:n 联系也要对应一张表。报告里购买表就是购买联系的转换结果,但开药联系没有对应的表,如果老师追问,你可以说开药记录通过医生表和药品表的关联查询实现,不单独建表。

6. 进阶技巧:用 T-SQL 脚本一键重建整个课设数据库

如果你想把这份课设真正跑起来,最省事的办法是写一个完整的 T-SQL 脚本,把建库、建表、建触发器、插测试数据、授权全部串起来。我一般会按这个顺序组织:

-- 1. 建库 IF DB_ID('PharmacyDB') IS NOT NULL DROP DATABASE PharmacyDB; CREATE DATABASE PharmacyDB; GO USE PharmacyDB; GO -- 2. 建表(略,见第 3 章脚本) -- 3. 插入测试数据 INSERT INTO Yisheng VALUES ('张医生', '35', '男'); INSERT INTO yaojishi VALUES ('李药师', '28', '女'); INSERT INTO yaopin VALUES ('YP001', '阿莫西林', '100', '2025-12', '华北制药', '25.50', '500', '10', '70', '300', '1200'); INSERT INTO guitai VALUES ('GT01', '王销售', 'E001', '一号柜台'); INSERT INTO guitaizhigong VALUES ('E001', '男', '30', '王销售', 'GT01', '4500'); INSERT INTO buy VALUES ('YP001', '2025-01-15'); GO -- 4. 建触发器(略,见第 3 章脚本) -- 5. 授权 CREATE LOGIN pharmacy_guest WITH PASSWORD = 'Guest@123'; CREATE USER pharmacy_guest FOR LOGIN pharmacy_guest; GRANT SELECT ON yaopin TO pharmacy_guest; GO -- 6. 验证查询 SELECT * FROM yaopin; SELECT * FROM buy; GO

这个脚本的好处是,你换一台机器、重装一次 SQL Server,只要把脚本贴进去执行,整个数据库就重建好了,不用手动一步步点。参数方面,测试数据里的药品号、柜台号、职工号都用了 char(8) 能容纳的短字符串,日期用 '2025-01-15' 这种格式,SQL Server 2008 默认能识别。如果你要批量插入几百条数据,建议用BULK INSERT或者写个循环,但课设演示十几条就够了。

还有一个技巧是给常用查询建索引。比如购买表的 medicineid 和 buydate 经常用于连接和筛选,可以加一个非聚集索引:

CREATE INDEX IX_buy_medicineid ON buy(medicineid); CREATE INDEX IX_buy_buydate ON buy(buydate);

这样在演示“查询某药品的购买记录”时,响应会快很多。不过课设数据量小,索引的效果不明显,但写进报告里能体现你考虑了物理结构设计。

从那以后我每次拿到课设题目,都先把建库脚本完整跑一遍,确认能建表、能插数据、触发器不报错,再回头写报告里的理论部分。因为报告写得再漂亮,演示时数据库连不上或者查询报错,整个课设就翻车了。希望这份拆解能帮你把药店管理系统的课设顺利跑通。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进