
简介这份数据库课程设计文档面向高校计算机相关专业学生与课程设计指导教师围绕公司或单位员工考勤管理系统展开帮助读者完成从需求分析到数据库落地的完整设计任务。压缩包内共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_nameemployee员工信息emp_id, emp_name, dept_id, hire_dateshift班次定义shift_id, shift_name, work_start, work_endattendance考勤记录att_id, emp_id, att_date, check_in, check_out, statusleave_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 ) ENGINEInnoDB; -- 员工表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) ) ENGINEInnoDB; -- 班次表定义上下班时间 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 ) ENGINEInnoDB; -- 考勤记录表核心表 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) ) ENGINEInnoDB; -- 请假记录表 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) ) ENGINEInnoDB;逻辑说明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. 增删改查与考勤统计把业务逻辑写成 SQL4.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连接串里加characterEncodingutf8Navicat 里检查连接属性的字符集设置。这个坑几乎每个人都会踩一次建库第一句就写对能省很多事。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 图才理顺。后来养成习惯建表前先把业务规则写成文字再翻译成字段返工少了很多。希望帮到你。本文还有配套的精品资源点击获取