简介:这份数据库课程设计文档面向高校计算机相关专业学生与课程设计指导教师,围绕公司或单位员工考勤管理系统展开,帮助读者完成从需求分析到数据库落地的完整设计任务。压缩包内共1个doc文件,约318KB,内容按章节组织,涵盖设计背景与研究目的、功能需求与数据流图、功能模块图与系统数据流程图、局部及整体E-R图、关系模式与数据关系图、存储记录结构与索引创建、数据库实施等模块,形成一套可直接参考的课程设计范本。目前已有4364人学习下载,适合需要撰写课程设计报告、梳理E-R图与关系模式、搭建考勤管理数据库的中级学习者,可据此理解需求到物理结构的完整设计链路,并对照完善自己的文档结构与图表表达。
1. 从一份 .doc 需求书到能跑的考勤系统:数据库课程设计到底在考什么
很多同学拿到“公司或单位员工考勤管理系统.doc”这个题目时,第一反应是去搜一套现成源码交差。但真正做过课程设计答辩的人都知道,老师翻两页就会问:你的表结构为什么这么设计?迟到早退怎么判定?一个人一天打四次卡你怎么存?这些问题答不上来,界面再漂亮也过不了。这个题目的本质不是让你写一个打卡 App,而是用考勤这个业务场景,把数据库课程设计里最核心的东西串起来:需求分析、E-R 建模、范式设计、增删改查、视图与存储过程、事务与并发。它适合数据库课程设计、软件工程课程设计阶段的学生,也适合想用一个完整案例把 SQL 捡起来的开发者。下面我按实际做一遍的顺序,把每一步讲清楚。
2. 考勤业务到底要存哪些数据:从需求到 E-R 图
2.1 先别急着建表,把考勤规则问清楚
考勤系统的坑,八成出在需求没问清就动手建表。我一般会先拿一张纸,把单位里真实发生的考勤行为列出来。常见的规则有这么几类:固定班制(早九晚六,一天两次卡)、多班次制(早班、中班、夜班,不同班次上下班时间不同)、弹性工作制(只要满足工时即可)。课程设计里最稳妥的是固定班制加少量加班和请假,规则简单、表结构清晰、答辩好讲。
需要落成字段的信息包括:员工是谁(工号、姓名、部门、入职日期)、属于哪个班次(班次名、上班时间、下班时间)、哪天打的卡(日期、打卡时间、打卡类型)、这次打卡算不算异常(迟到、早退、缺卡、正常)、请假和加班怎么记(类型、起止时间、审批状态)。把这些写成需求条目,后面建表就是照着翻译。
提示:课程设计里不要一上来就做“智能排班”“跨天夜班”这种复杂逻辑,判定规则一复杂,SQL 里全是边界条件,答辩时自己都讲不清。
2.2 E-R 图怎么画才不会被挑毛病
E-R 图是数据库课程设计的必考项,画的时候抓住实体、属性、联系三要素。这个系统里核心实体有四个:员工(Employee)、部门(Department)、班次(Shift)、考勤记录(Attendance)。联系上,一个部门有多名员工(1:N),一个班次可以分配给多名员工(1:N),一名员工有多条考勤记录(1:N)。请假和加班可以单独做成两张表,也可以合并成一张“异常申请”表,课程设计里分开做更清楚。
画图时容易犯的错是把“迟到”当成一个实体。迟到是考勤记录的一个状态属性,不是独立实体。另一个错是把打卡时间直接塞进员工表,那样一个员工只能存一条记录,完全没法用。正确做法是考勤记录表用外键指向员工,一个员工对应多行记录。
下面这张表是我做这个题目时最终确定的表清单,字段做了精简,够用且不臃肿:
| 表名 | 作用 | 关键字段 |
|---|---|---|
| department | 部门信息 | dept_id, dept_name |
| employee | 员工信息 | emp_id, emp_name, dept_id, hire_date |
| shift | 班次定义 | shift_id, shift_name, work_start, work_end |
| attendance | 考勤记录 | att_id, emp_id, att_date, check_in, check_out, status |
| leave_record | 请假记录 | leave_id, emp_id, leave_type, start_time, end_time, approve_status |
字段类型上,日期用 DATE,时间点用 DATETIME 或 TIME,状态用 VARCHAR 存中文或 TINYINT 存编码都行,课程设计里用 VARCHAR 更直观。主键统一用自增整数,外键加索引,这些细节答辩时都是加分项。
3. 用 MySQL 建库建表:一份能直接跑的 DDL 脚本
3.1 建库与建表语句
选 MySQL 是因为它安装简单、资料多、课程设计里最通用。下面这份脚本可以直接在 Navicat 或命令行里执行,建库、建表、加约束一次到位。
-- 创建数据库,字符集用 utf8mb4 避免中文乱码 CREATE DATABASE attendance_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE attendance_db; -- 部门表 CREATE TABLE department ( dept_id INT PRIMARY KEY AUTO_INCREMENT, dept_name VARCHAR(50) NOT NULL UNIQUE ) ENGINE=InnoDB; -- 员工表,dept_id 外键指向部门 CREATE TABLE employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT, emp_name VARCHAR(30) NOT NULL, dept_id INT, hire_date DATE, CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES department(dept_id) ) ENGINE=InnoDB; -- 班次表,定义上下班时间 CREATE TABLE shift ( shift_id INT PRIMARY KEY AUTO_INCREMENT, shift_name VARCHAR(20) NOT NULL, work_start TIME NOT NULL, work_end TIME NOT NULL ) ENGINE=InnoDB; -- 考勤记录表,核心表 CREATE TABLE attendance ( att_id INT PRIMARY KEY AUTO_INCREMENT, emp_id INT NOT NULL, att_date DATE NOT NULL, check_in DATETIME, check_out DATETIME, status VARCHAR(10) DEFAULT '正常', CONSTRAINT fk_att_emp FOREIGN KEY (emp_id) REFERENCES employee(emp_id), UNIQUE KEY uk_emp_date (emp_id, att_date) ) ENGINE=InnoDB; -- 请假记录表 CREATE TABLE leave_record ( leave_id INT PRIMARY KEY AUTO_INCREMENT, emp_id INT NOT NULL, leave_type VARCHAR(10), start_time DATETIME, end_time DATETIME, approve_status VARCHAR(10) DEFAULT '待审批', CONSTRAINT fk_leave_emp FOREIGN KEY (emp_id) REFERENCES employee(emp_id) ) ENGINE=InnoDB;逻辑说明:attendance表上的UNIQUE KEY uk_emp_date (emp_id, att_date)是关键约束,它保证一个员工一天只有一条考勤记录,避免重复打卡产生脏数据。外键约束保证员工和部门、考勤和员工之间的引用完整性。参数上,VARCHAR(10)存状态够用,DATETIME存打卡时间点比TIME更灵活,因为跨天打卡时日期信息不会丢。
3.2 插入测试数据
建完表要灌一批数据才能验证后面的查询。测试数据要覆盖正常、迟到、早退、缺卡几种情况,不然查询写出来看不出对错。
INSERT INTO department (dept_name) VALUES ('技术部'), ('人事部'), ('财务部'); INSERT INTO employee (emp_name, dept_id, hire_date) VALUES ('张三', 1, '2023-03-01'), ('李四', 1, '2023-05-15'), ('王五', 2, '2022-11-20'); INSERT INTO shift (shift_name, work_start, work_end) VALUES ('标准班', '09:00:00', '18:00:00'); INSERT INTO attendance (emp_id, att_date, check_in, check_out, status) VALUES (1, '2024-06-03', '2024-06-03 08:55:00', '2024-06-03 18:05:00', '正常'), (1, '2024-06-04', '2024-06-04 09:20:00', '2024-06-04 18:00:00', '迟到'), (2, '2024-06-03', '2024-06-03 09:00:00', '2024-06-03 17:30:00', '早退'), (2, '2024-06-04', NULL, '2024-06-04 18:00:00', '缺卡');逻辑说明:这里故意造了迟到、早退、缺卡三种异常,后面写统计查询时能直接看到结果。check_in为 NULL 表示上班没打卡,这是缺卡的典型场景。参数上,日期统一用2024-06-03这种格式,MySQL 会自动转换,不用手动拼字符串。
4. 增删改查与考勤统计:把业务逻辑写成 SQL
4.1 基础增删改查
课程设计答辩必问增删改查,这部分要写得干净。查询员工完整信息要关联部门表,不然只显示 dept_id 看不出是哪个部门。
-- 查:员工及其部门名称 SELECT e.emp_id, e.emp_name, d.dept_name, e.hire_date FROM employee e LEFT JOIN department d ON e.dept_id = d.dept_id; -- 增:新增一名员工 INSERT INTO employee (emp_name, dept_id, hire_date) VALUES ('赵六', 3, '2024-06-01'); -- 改:调整员工部门 UPDATE employee SET dept_id = 1 WHERE emp_id = 4; -- 删:删除一条考勤记录 DELETE FROM attendance WHERE att_id = 4;逻辑说明:查询用LEFT JOIN而不是INNER JOIN,是为了防止员工没分配部门时整条记录查不出来。删除操作在实际系统里一般做逻辑删除(加 is_deleted 字段),课程设计里物理删除也能接受,但答辩时提一句逻辑删除会显得有工程意识。
4.2 考勤统计查询
考勤系统的价值在统计,这部分是重点。常见的统计需求有三个:某员工某月迟到几次、某部门某天出勤率、某员工月度考勤明细。
-- 统计每位员工 6 月的迟到次数 SELECT e.emp_name, COUNT(*) AS late_count FROM attendance a JOIN employee e ON a.emp_id = e.emp_id WHERE a.status = '迟到' AND a.att_date BETWEEN '2024-06-01' AND '2024-06-30' GROUP BY e.emp_id, e.emp_name; -- 统计某天各部门出勤人数 SELECT d.dept_name, COUNT(a.att_id) AS attend_count FROM department d LEFT JOIN employee e ON d.dept_id = e.dept_id LEFT JOIN attendance a ON e.emp_id = a.emp_id AND a.att_date = '2024-06-03' GROUP BY d.dept_id, d.dept_name;逻辑说明:第一个查询用GROUP BY按员工分组计数,BETWEEN限定月份范围。第二个查询用两次LEFT JOIN,保证没有考勤记录的部门也显示为 0,而不是直接消失。参数上,日期范围用字符串比较即可,MySQL 会隐式转换,但更规范的做法是用STR_TO_DATE显式转换。
4.3 用视图封装常用统计
如果统计查询反复用,可以做成视图,调用时只写一句SELECT * FROM v_xxx。视图在课程设计里是加分项,能体现你对数据库对象的理解。
-- 创建月度考勤汇总视图 CREATE VIEW v_monthly_attendance AS SELECT e.emp_id, e.emp_name, DATE_FORMAT(a.att_date, '%Y-%m') AS month, SUM(CASE WHEN a.status = '正常' THEN 1 ELSE 0 END) AS normal_days, SUM(CASE WHEN a.status = '迟到' THEN 1 ELSE 0 END) AS late_days, SUM(CASE WHEN a.status = '早退' THEN 1 ELSE 0 END) AS early_days, SUM(CASE WHEN a.status = '缺卡' THEN 1 ELSE 0 END) AS miss_days FROM attendance a JOIN employee e ON a.emp_id = e.emp_id GROUP BY e.emp_id, e.emp_name, DATE_FORMAT(a.att_date, '%Y-%m'); -- 调用视图查张三的月度汇总 SELECT * FROM v_monthly_attendance WHERE emp_name = '张三';逻辑说明:视图里用CASE WHEN做条件计数,这是 SQL 里统计分类数据的标准写法,比写多个子查询高效。DATE_FORMAT把日期截断到月份,作为分组维度。参数上,%Y-%m输出2024-06这种格式,方便阅读和排序。
5. 考勤系统开发避坑:那些答辩被问住的瞬间
5.1 打卡时间存成字符串导致比较出错
现象:查询“迟到”记录时,明明 09:20 打卡,结果查不出来。原因:check_in字段建表时用了VARCHAR,字符串比较'09:20' > '09:00'在某些格式下会出错,比如存成'9:20'就比'09:00'小。解决:时间字段一律用DATETIME或TIME类型,让数据库负责比较,不要自己拼字符串。
5.2 一个员工一天多条记录导致统计翻倍
现象:统计迟到次数时,张三明明只迟到一次,结果显示 2。原因:attendance表没加(emp_id, att_date)唯一约束,测试时重复插入了数据。解决:建表时加UNIQUE KEY uk_emp_date (emp_id, att_date),从数据库层面杜绝重复。已经建好表的可以用ALTER TABLE attendance ADD UNIQUE KEY uk_emp_date (emp_id, att_date);补上。
5.3 外键约束导致删数据失败
现象:想删一个部门,报错Cannot delete or update a parent row。原因:该部门下还有员工,外键约束阻止删除。解决:要么先删或转移该部门下的员工,要么建表时把外键写成ON DELETE SET NULL或ON DELETE CASCADE。课程设计里建议用SET NULL,删部门不删员工,只是把员工的 dept_id 置空,更符合业务逻辑。
5.4 中文乱码
现象:插入“技术部”,查出来是问号。原因:建库时没指定字符集,或者连接时字符集不匹配。解决:建库用utf8mb4,连接串里加characterEncoding=utf8,Navicat 里检查连接属性的字符集设置。这个坑几乎每个人都会踩一次,建库第一句就写对能省很多事。
5.5 统计查询把 NULL 当成 0 处理
现象:缺卡记录check_in是 NULL,用check_in > '09:00'判断时,NULL 不参与比较,缺卡的人既不算迟到也不算正常,统计里消失了。解决:用IFNULL(check_in, '23:59:59')或CASE WHEN check_in IS NULL THEN '缺卡'显式处理 NULL。记住 SQL 里 NULL 和任何值比较结果都是 NULL,不是 TRUE 也不是 FALSE。
6. 把课程设计做成能讲清楚的作品:存储过程与答辩技巧
做到上面这一步,系统已经能跑、能查、能统计了。但课程设计想拿高分,还得有一两个能讲出深度的点。我一般会加一个存储过程,把“根据打卡时间自动判定考勤状态”这个逻辑封装进去,答辩时现场调用一次,比干讲表结构有说服力。
DELIMITER // CREATE PROCEDURE judge_attendance(IN p_emp_id INT, IN p_date DATE) BEGIN DECLARE v_check_in DATETIME; DECLARE v_check_out DATETIME; DECLARE v_status VARCHAR(10); SELECT check_in, check_out INTO v_check_in, v_check_out FROM attendance WHERE emp_id = p_emp_id AND att_date = p_date; IF v_check_in IS NULL OR v_check_out IS NULL THEN SET v_status = '缺卡'; ELSEIF TIME(v_check_in) > '09:00:00' THEN SET v_status = '迟到'; ELSEIF TIME(v_check_out) < '18:00:00' THEN SET v_status = '早退'; ELSE SET v_status = '正常'; END IF; UPDATE attendance SET status = v_status WHERE emp_id = p_emp_id AND att_date = p_date; END // DELIMITER ; -- 调用:判定张三 6 月 4 日的考勤状态 CALL judge_attendance(1, '2024-06-04');逻辑说明:存储过程里用IF...ELSEIF...ELSE做多分支判定,TIME()函数把 DATETIME 截出时间部分再和班次时间比较。参数p_emp_id和p_date是输入参数,调用时传入。这个过程的判定规则写死了 09:00 和 18:00,更完善的做法是从shift表里查出来,但课程设计里写死也能讲清楚逻辑,答辩时说明“实际项目会从班次表动态读取”即可。
答辩时还有几个技巧。第一,主动讲你的 E-R 图,从实体到联系再到范式,这是数据库课程设计的核心考点。第二,准备一条复杂查询,现场写出来并解释执行逻辑,比如“查每个部门迟到次数最多的员工”。第三,把踩过的坑讲出来,比如上面说的 NULL 比较问题,老师会觉得你真的动手做过。第四,别把界面当重点,课程设计考的是数据库设计,界面能用就行。
我自己做这个题目时,第一版表结构把打卡时间直接塞进员工表,被老师一句“一个人只能打一次卡吗”问住了,回来重画 E-R 图才理顺。后来养成习惯,建表前先把业务规则写成文字,再翻译成字段,返工少了很多。希望帮到你。
本文还有配套的精品资源,点击获取