简介:这份家庭财务管理系统数据库课程设计文档,面向计算机应用与技术等专业的学生及需要完成数据库课程设计的自学者,帮助解决从需求分析到逻辑结构、物理结构落地的完整设计流程问题。资源包共1个docx文件,约321KB,内容为课程设计说明书,涵盖需求分析、三层数据流图、数据字典与数据结构等核心章节。文档中详细梳理了管理员与普通用户之间的数据流向,给出第1层至第3层DFD的细化过程,并整理出33个数据项与33个数据结构,涉及用户、收入来源、支出类型、日常收支、活期与定期账户、借入借出款及银行账户等实体,同时包含E-R图概念结构设计思路。读者可据此获得一套可直接参考的数据库课程设计框架,用于理解数据流图分层方法、数据字典编写规范以及概念模型到逻辑模型的转换过程,适合作为课程设计报告撰写与数据库建模练习的对照材料。目前已有405人学习下载。
1. 从一份只有图片缺失的课设说明书说起:这套家庭财务管理系统数据库到底能跑通什么
如果你正在搜“家庭财务管理系统数据库课程设计”,大概率不是想听数据库概论,而是手里已经有一份需求分析、DFD 分层图、数据字典和 11 张表的字段清单,却卡在“怎么把它变成能跑的库”这一步。这份资源的价值就在这:它给全了从第 1 层到第 3 层的数据流图、33 个数据项、11 张表的逻辑结构,以及建库、建表、存储过程、触发器四段可直接抄的 SQL 骨架。它适合两类人——要交数据库课设、需要一份结构完整且能自圆其说的设计文档的在校生,以及想拿一个“家庭记账”小系统练手 SQL Server 建表与存储过程的初学者。它不解决前端界面,也不解决报表美化,它解决的是“数据从哪来、存到哪张表、怎么查出来”这条链路。
2. 需求分析到三层 DFD:把“管理员录入、用户查询”翻译成数据流
2.1 为什么先画 DFD 再建表,而不是直接写 CREATE TABLE
很多人拿到课设第一反应是打开数据库客户端直接敲建表语句,结果字段名和业务对不上,改到第三遍才发现“收入来源”和“收入类型”是两个东西。这份设计先做需求分析,把“管理员”定为数据源点、“普通用户”定为数据终点,再逐层细化,本质是逼你在写 SQL 之前先把数据流向想清楚。第 1 层 DFD 只有“家庭财务管理”一个加工,输入是用户信息、理财信息、日常管理信息,输出是统计报告结果;第 2 层把它拆成“录入用户信息”“录入理财项目信息”“录入日常管理信息”“统计报告”四个加工,并挂上“用户”“理财”“日常管理”三个数据存储;第 3 层再把“统计报告”拆成“合法性检查”和“统计”两步。这个拆法对应到代码里,就是后面 11 张表按“基础信息表 + 流水表 + 账户表 + 借贷表”四类落库。
常见做法是:先按 DFD 的加工确定“谁写哪张表”,再按数据存储确定“表与表怎么关联”。比如“录入日常管理信息”这个加工,写的就是 DailyIncome 和 DailyOutput 两张流水表;“统计报告”这个加工,读的是流水表加账户表,不写新表。把加工和表的读写关系列成一张对照表,建表时就不会漏字段。
| DFD 加工 | 写入的表 | 读取的表 |
|---|---|---|
| 录入用户信息 | Family | Family |
| 录入理财项目信息 | IncomeType、OutputType | IncomeType、OutputType |
| 录入日常管理信息 | DailyIncome、DailyOutput | Family、IncomeType、OutputType |
| 统计报告 | 无 | DailyIncome、DailyOutput、LiveAction、FixAction |
2.2 数据字典里 33 个数据项,哪些必须原样保留
数据字典是这份课设最容易被忽略、却最影响建表质量的部分。原文列了 33 个数据项,其中真正会进 SQL 的字段类型集中在 int、nvarchar、datetime、float 四种。这里有两个坑:一是“收入金额”在数据项里写 float 长度 16,但到了表 4-2 IncomeType 里被写成 int 长度 4,前后不一致;二是“支出金额”在数据项里是 float,表 4-3 OutputType 里也变成 int。如果你照抄表结构,金额字段会丢小数,记账系统里一分钱对不上就是血泪经验。我的处理方式是:以数据字典的 float 为准,表结构里统一改成 float 或 decimal,长度按 8 或 16 给。
另一个必须原样保留的是主键命名规则。11 张表的主键都叫“表名 + ID”,比如 Family 表主键 FamilyID、LiveBank 表主键 LiveBankID。这个规则看着啰嗦,但好处是外键引用时一眼能看出指向哪张表,后面写多表统计 SQL 时不用反复翻字段清单。数据字典里的“数据结构”部分,比如“日常收入:编号+收入日期+收入人员+收入来源+收入金额+备注”,其实就是建表时的字段顺序,照着排就行。
2.3 从 E-R 图到 11 张表的映射规则
E-R 图里画了用户信息、收入来源、支出类型、日常收入、日常支出、活期银行账户、定期银行账户等实体,实体之间用菱形联系。映射到关系表时,这份设计用的是最直接的一套规则:一个实体一张表,多对多联系拆成独立表或外键。具体到 11 张表,可以分成四组理解。
第一组是基础字典表:Family(家庭成员)、IncomeType(收入来源)、OutputType(支出类型)。这三张表数据量小,主要给流水表提供外键。第二组是流水表:DailyIncome(日常收入)、DailyOutput(日常支出),字段里 DailyIncomeName 和 DailyIncomeType 是 int,指向 Family 和 IncomeType 的主键。第三组是账户表:LiveBank、FixBank 存账户基本信息,LiveAction、FixAction 存存取款流水,账户表和操作表通过账户编号关联。第四组是借贷表:LendMoney(借出)、BorrowMoney(借入),两张表结构对称,只是出借人和借贷人字段互换。
提示:E-R 图里“活期账户信息实体”和“活期银行账户信息实体”是两个实体,对应到表就是 LiveAction 和 LiveBank,别合并成一张,否则账户余额和每笔流水混在一起,统计时算不清。
3. 建库建表实操:11 张表的 SQL 落地与字段类型修正
3.1 建库与建表顺序:先字典表,后流水表
建表顺序不是随便排的,有外键依赖时必须先建被引用的表。这份设计里 Family、IncomeType、OutputType 是三张基础表,DailyIncome 和 DailyOutput 引用它们,所以先建前三张。LiveBank 和 FixBank 不依赖别的表,可以紧随其后。LiveAction 和 FixAction 引用账户表,LendMoney 和 BorrowMoney 引用 Family,放最后。下面这段 SQL 按这个顺序给出核心几张表的建法,字段类型已按数据字典把金额统一成 float。
-- 建库,库名沿用原文的 student CREATE DATABASE student; GO USE student; GO -- 1. 家庭成员表,主键 FamilyID CREATE TABLE Family ( FamilyID INT PRIMARY KEY, FamilyName NVARCHAR(50) NOT NULL, FamilyPwd NVARCHAR(50), FamilyType INT, FamilyBZ NVARCHAR(50) ); -- 2. 收入来源表,注意金额字段用 float,不用 int CREATE TABLE IncomeType ( IncomeTypeID INT PRIMARY KEY, IncomeTypeType NVARCHAR(50), IncomeTypeDate DATETIME, IncomeTypeMember NVARCHAR(50), IncomeTypeSum FLOAT, IncomeBZ NVARCHAR(50) ); -- 3. 日常收入表,收入人员、收入来源用 int 指向基础表 CREATE TABLE DailyIncome ( DailyIncomeID INT PRIMARY KEY, DailyIncomeDate DATETIME, DailyIncomeName INT, DailyIncomeType INT, DailyIncomeNum FLOAT, DailyIncomeBZ NVARCHAR(50) ); -- 4. 活期账户操作表,存取金额默认 0 CREATE TABLE LiveAction ( LiveActionID INT PRIMARY KEY, LiveActionNo INT, LiveActionDate DATETIME, LiveActionName INT, LiveActionCun FLOAT DEFAULT 0, LiveActionQu FLOAT DEFAULT 0, LiveActionBZ NVARCHAR(50) );逻辑说明:CREATE DATABASE 建库后必须 USE 切过去,否则表会建到 master 里。Family 表 FamilyID 设为主键,FamilyName 设 NOT NULL,因为后面流水表要靠人员编号关联,姓名不能空。IncomeType 的 IncomeTypeSum 改成 FLOAT,这是对原文表 4-2 写 int 的修正。DailyIncome 的 DailyIncomeName 和 DailyIncomeType 用 INT,对应 Family 和 IncomeType 的主键,方便后面 JOIN。LiveAction 的 LiveActionCun 和 LiveActionQu 加 DEFAULT 0,原文明确要求默认值为 0,这样插入时只写支出不写存入也不会报 NULL。
参数说明:NVARCHAR(50) 用于中文姓名和备注,50 个字符够用;DATETIME 存日期,原文数据长度写 8,SQL Server 里 DATETIME 固定占 8 字节,不用手动指定;FLOAT 存金额,如果对精度要求高可以换 DECIMAL(18,2),但课设场景 FLOAT 够用。剩下 7 张表按同样规则补全即可,FixBank、FixAction、LendMoney、BorrowMoney 的字段直接对照原文表 4-5 到表 4-11 抄,注意 LendMoney 和 BorrowMoney 的日期字段是 DATETIME,金额是 FLOAT。
3.2 存储过程:查询家庭成员与插入日常收入
原文给了三个存储过程骨架,但语法有缺漏,比如 stu_info 里 SELECT 写成了“FamilyID,FamilyName,FamilyBZ select from Family”,顺序反了。下面给出修正后可执行的版本。
-- 存储过程一:查询所有家庭成员的编号、姓名、备注 CREATE PROCEDURE stu_info AS BEGIN SELECT FamilyID, FamilyName, FamilyBZ FROM Family; END GO -- 存储过程二:向 DailyIncome 插入一条记录 CREATE PROCEDURE insertdata @param1 INT, @param2 DATETIME, @param3 INT, @param4 INT, @param5 FLOAT, @param6 NVARCHAR(50) AS BEGIN INSERT INTO DailyIncome (DailyIncomeID, DailyIncomeDate, DailyIncomeName, DailyIncomeType, DailyIncomeNum, DailyIncomeBZ) VALUES (@param1, @param2, @param3, @param4, @param5, @param6); END GO逻辑说明:第一个存储过程无参数,直接 SELECT 三列,适合做“查看成员列表”的按钮后端。第二个存储过程六个参数对应 DailyIncome 六个字段,参数类型和表字段一一对应,@param5 用 FLOAT 接金额。原文里 insertdata 的 INSERT 写成了“insert into sc(...)”,表名 sc 是错的,这里改成 DailyIncome。调用时用 EXEC insertdata 1, '2024-01-01', 1, 1, 500.00, '工资',六个参数按顺序给。
参数说明:@param1 是编号,调用时自己保证不重复,因为主键约束会拦重复值;@param2 是日期,传字符串时 SQL Server 会隐式转 DATETIME,格式建议用 YYYY-MM-DD;@param3 和 @param4 是人员编号和收入来源编号,传之前要确认 Family 和 IncomeType 里有对应记录,否则逻辑上对不上,虽然没建外键不会报错,但统计时会查出孤儿数据。
3.3 触发器:插入、删除、更新三类动作的写法与风险
原文给了四个触发器,但有两个明显问题:delete_family 写的是 AFTER INSERT 却执行 DELETE,update_family 也是 AFTER INSERT 却执行 UPDATE,触发时机和动作对不上。正确做法是删除用 AFTER DELETE,更新用 AFTER UPDATE。下面给出修正版。
-- 插入触发器:插入后打印提示 CREATE TRIGGER insert_family ON Family AFTER INSERT AS BEGIN PRINT '数据插入成功'; END GO -- 删除触发器:删除后打印提示 CREATE TRIGGER delete_family ON Family AFTER DELETE AS BEGIN PRINT '数据删除成功'; END GO -- 更新触发器:更新后打印提示 CREATE TRIGGER update_family ON Family AFTER UPDATE AS BEGIN PRINT '数据更新成功'; END GO逻辑说明:触发器挂在 Family 表上,AFTER INSERT 表示插入完成后触发,PRINT 只做提示,不改变数据。原文里 delete_family 和 update_family 都写成 AFTER INSERT,如果照抄,删除和更新时触发器根本不会触发,调试时会以为触发器失效。改成 AFTER DELETE 和 AFTER UPDATE 后才对得上动作。另外原文 update_family 里用 familyname like '李晓莉' 做条件,实际业务里应该用主键或参数,硬编码姓名在真实系统里是坑,课设演示可以保留但要知道边界。
参数说明:触发器里没有参数,靠 inserted 和 deleted 两个临时表拿变更数据。如果要在触发器里做级联操作,比如删除家庭成员时同时删他的流水,可以用 deleted.FamilyID 关联 DailyIncome 做 DELETE。但要注意触发器里做级联删除容易引发递归,SQL Server 默认递归触发器关闭,嵌套超过 32 层会报错,课设场景建议只做提示,不做级联。
4. 避坑与排查:字段类型、触发器时机、存储过程参数三类翻车现场
4.1 金额字段写成 int,小数被截断
现象:插入一笔 500.50 的收入,查出来变成 500,对账差 0.5。原因:原文表 4-2 和表 4-3 把收入金额、支出金额写成 int 长度 4,而数据字典里是 float 长度 16,两处矛盾,照抄表结构就会丢小数。解决:建表时金额字段统一用 FLOAT 或 DECIMAL(18,2),以数据字典为准,表结构里的 int 是笔误。改完后重新插入验证,SELECT 出来带小数才算过。
4.2 触发器 AFTER INSERT 配 DELETE 动作,删除时不触发
现象:执行 DELETE FROM Family 后没有任何提示,以为触发器没建成功。原因:触发器定义写的是 AFTER INSERT,只有插入才触发,删除动作不触发。解决:删除用 AFTER DELETE,更新用 AFTER UPDATE,插入用 AFTER INSERT,三者不能混。改完后用对应语句各测一次,看到 PRINT 输出才算对。
4.3 存储过程参数顺序和表字段顺序不一致
现象:调用 insertdata 后数据插进去了,但日期列显示的是人员编号,金额列显示的是日期。原因:存储过程参数按 @param1 到 @param6 顺序传,INSERT 时 VALUES 里字段顺序和参数顺序没对齐。解决:INSERT 的字段列表和 VALUES 的参数列表按同一顺序写,或者用 @参数名 = 值 的方式调用,避免位置错乱。改完后 SELECT 出来逐列核对。
4.4 建表顺序颠倒,外键引用报错
现象:先建 DailyIncome 再建 Family,如果加了外键约束会报“引用的表不存在”。原因:有外键依赖时,被引用的表必须先建。解决:按 Family、IncomeType、OutputType、LiveBank、FixBank、DailyIncome、DailyOutput、LiveAction、FixAction、LendMoney、BorrowMoney 的顺序建。课设里如果没加外键约束不会报错,但逻辑上仍然应该按依赖顺序建,方便后面加约束。
4.5 统计 SQL 用错关联字段,收入支出对不上
现象:统计每月收入时,把 DailyIncome 和 DailyOutput 用日期直接关联,结果同一天有多笔收支时出现笛卡尔积,金额翻倍。原因:两张流水表没有直接关联字段,应该各自按日期分组求和,再合并结果。解决:用两个子查询分别算月收入、月支出,再用日期做 FULL JOIN,或者用 UNION ALL 合并后按类型分组。不要用 INNER JOIN 直接连两张流水表。
5. 统计报表的进阶写法:从单表查询到多表关联的验证方法
课设做到最后,老师大概率会问“统计报表怎么实现的”。原文功能模块图里列了每月收入、每月支出、活期账户、定期账户、借出款、借入款六类统计,还要求按日期、经手人、金额查询。这里给一个可验证的进阶写法:先写单表分组,再写多表关联,最后用已知数据反推结果对不对。
先看每月收入统计,按 DailyIncomeDate 的月份分组,SUM 金额。
-- 每月收入统计:按年月分组求和 SELECT CONVERT(VARCHAR(7), DailyIncomeDate, 120) AS 月份, SUM(DailyIncomeNum) AS 月收入 FROM DailyIncome GROUP BY CONVERT(VARCHAR(7), DailyIncomeDate, 120) ORDER BY 月份;逻辑说明:CONVERT 把 DATETIME 转成 'YYYY-MM' 格式,120 是 ODBC 标准格式代码。GROUP BY 用同样的表达式,SUM 对金额求和。验证方法:手动插三条同月记录,金额分别是 100、200、300,查出来应该是 600;再插一条下月记录 50,查出来两行,一行 600 一行 50。
再看活期账户余额验证,这是课设里最容易算错的地方。LiveBank 表存初始金额和余额,LiveAction 表存每笔存取。正确逻辑是:账户余额 = 初始金额 + 所有存入金额 - 所有支出金额。写一条校验 SQL,把算出来的余额和 LiveBank 里存的余额对比,不一致就说明流水有问题。
-- 校验活期账户余额:初始金额 + 存入 - 支出 应等于表里余额 SELECT b.LiveBankID, b.LiveBankChu AS 初始金额, ISNULL(SUM(a.LiveActionCun), 0) AS 累计存入, ISNULL(SUM(a.LiveActionQu), 0) AS 累计支出, b.LiveBankChu + ISNULL(SUM(a.LiveActionCun), 0) - ISNULL(SUM(a.LiveActionQu), 0) AS 计算余额, b.LiveBankYu AS 表内余额 FROM LiveBank b LEFT JOIN LiveAction a ON b.LiveBankID = a.LiveActionNo GROUP BY b.LiveBankID, b.LiveBankChu, b.LiveBankYu;逻辑说明:LEFT JOIN 保证没有流水的账户也能查出来,ISNULL 把 NULL 转成 0,否则 SUM 遇到 NULL 整行变 NULL。计算余额和表内余额两列并排显示,肉眼就能看出哪条对不上。参数说明:LiveActionNo 是账户编号,对应 LiveBank 的主键 LiveBankID,关联字段别用错,用成 LiveActionID 就变成按流水编号关联,结果全错。
我一般会再补一个按经手人筛选的统计,因为原文功能模块图里明确要求“按日期、经手人、金额”查询。经手人在 LiveAction 表里是 LiveActionName,类型 int,指向 Family 主键。写的时候 JOIN Family 拿姓名,WHERE 里加日期范围和经手人编号。
-- 按经手人和日期范围统计活期流水 SELECT f.FamilyName AS 经手人, a.LiveActionDate AS 日期, a.LiveActionCun AS 存入, a.LiveActionQu AS 支出 FROM LiveAction a JOIN Family f ON a.LiveActionName = f.FamilyID WHERE a.LiveActionDate BETWEEN '2024-01-01' AND '2024-12-31' AND a.LiveActionName = 1 ORDER BY a.LiveActionDate;逻辑说明:JOIN Family 把经手人编号换成姓名,WHERE 两个条件分别过滤日期和经手人。BETWEEN 包含两端,日期格式用 YYYY-MM-DD 避免歧义。验证方法:先插一条经手人编号为 1 的记录,再插一条编号为 2 的,查询条件写 1,结果只应出现编号 1 那条。
最后说一个我踩过的坑:统计报表里日期字段用 DATETIME,如果插入时只写日期不写时间,SQL Server 默认补 00:00:00,按天分组没问题;但如果插入时带了时间,比如 '2024-01-01 15:30:00',用 CONVERT(VARCHAR(10), date, 120) 分组会把它归到 2024-01-01,用 DATEPART 按天分组也一样,但用等号比较 '2024-01-01' 就查不到。从那以后我每次做日期统计都强制走一遍 CONVERT 截断到天或月,再分组,不直接拿 DATETIME 做等值比较。希望帮到你。
本文还有配套的精品资源,点击获取