简介这份数据库课程设计文档面向高校计算机相关专业学生与需要完成课程设计的开发者围绕公司或单位员工考勤管理系统展开帮助解决从需求分析到数据库落地的完整设计问题。压缩包内共1个doc文件约318KB内容以课程设计报告形式呈现涵盖概述、需求分析、概念结构设计、逻辑结构设计、物理结构设计与数据库实施等章节并配有数据流图、功能模块图、局部与整体E-R图、关系模式及索引创建等设计成果。读者可据此掌握考勤管理中出勤、请假、加班等信息的建模思路理解数据库设计与软件工程理论在实际项目中的应用并参考其目录结构与图表组织方式完成自己的课程设计报告。目前已有4364人学习下载适合作为数据库课程设计的参考范本与排错对照资料。1. 从一份 .doc 到可跑的考勤库这套课程设计到底能省多少事如果你正在搜“数据库课程设计公司或单位员工考勤”大概率不是想听考勤制度怎么定而是手里压着一个必须交的数据库课设或者想拿一套现成的库表结构改改就用。这份资源是一份完整的 Word 文档围绕“公司或单位员工考勤管理系统”展开从需求分析、E-R 图、关系模式一路写到建库建表、存储过程和触发器技术栈锁定在 SQL Server 2005。它解决的不是“考勤业务怎么做”这种管理问题而是“一个考勤库从概念模型到物理落地每一步该画什么图、建什么表、写什么约束”这种工程问题。适合数据库课程设计的学生、刚接触 SQL Server 的初级开发以及需要快速搭一套考勤数据模型做原型验证的从业者。文档里最值钱的部分不是文字是那几张 E-R 图和六张表的字段定义——它们直接决定了你后面写查询、做统计时会不会被坑。2. 需求到 E-R把考勤业务拆成六张表的逻辑2.1 功能需求怎么落到实体上文档把功能需求拆成五块数据管理、考勤管理、加班管理、请假管理、出差管理。这五块听起来像模块但落到数据库设计上真正要解决的是“哪些东西需要独立成表、哪些只是字段”。我一般会先问三个问题这个对象有没有独立的生命周期它和员工是不是一对多它需不需要单独统计按这个标准过一遍员工基本信息独立成表没争议出勤记录、出差记录、加班记录、请假记录都是员工在特定时间段内的行为各自独立成表月统计是汇总结果也独立成表。文档里给出的关系模式正好是六张表职工、出勤记录、出差记录、加班信息、请假信息、月统计。这个拆分粒度是合理的既没有把请假和出差揉成一张“异常记录表”导致字段大量为空也没有把月统计拆成四张表增加连接成本。2.2 局部 E-R 图到整体 E-R 图的合并逻辑文档先画了六张局部 E-R 图再合并成整体 E-R 图。这个顺序不是形式主义它对应的是实际设计时的思考过程先单独看每个实体的属性再看实体之间的联系。员工实体的属性是职工编号、姓名、性别、年龄、职称出勤实体的属性是上班时间、下班时间、缺勤记录出差实体是开始时间、结束时间、统计天数加班实体是开始时间、结束时间、时间统计请假实体是开始时间、结束时间、统计天数月统计实体是出勤月统计、出差月统计、加班月统计、请假月统计。合并的时候员工编号作为主键贯穿所有表其他五张表通过员工编号和员工表建立一对多联系。这里有一个容易翻车的地方文档里出勤记录、出差记录、加班记录、请假记录都用了“员工编号业务编号”的复合主键而不是单独的业务编号做主键。这种设计在考勤场景下是合理的因为同一个员工在同一个月内可能有多条出勤、多条请假用复合主键能天然保证“同一员工同一业务编号不重复”。但如果你后面要改成 MySQL 或者用自增主键这个约束逻辑就得重新想。2.3 关系模式里的字段类型选择文档在物理结构设计部分给出了六张表的字段类型和约束。职工表用 CHAR(4) 存职工编号CHAR(6) 存姓名CHAR(2) 存性别并加了 CHECK 约束只允许“男”或“女”年龄用 INT职称用 CHAR(4)。出勤记录表用 CHAR(4) 存职工编号INT 存出勤编号DATETIME 存上下班时间缺勤记录也用 DATETIME。出差、加班、请假三张表的字段结构类似都是职工编号业务编号做复合主键时间字段用 DATETIME统计天数用 INT。月统计表用 CHAR(6) 存职工编号四个统计字段用 INT。这里有几个参数值得注意职工编号用 CHAR(4) 意味着最多 9999 个员工对中小型企业够用但如果你的课设要求支持万人以上这个长度就得改。姓名用 CHAR(6) 只能存三个汉字遇到复姓或者少数民族姓名可能不够实际项目里我一般会用 NVARCHAR(20)。性别用 CHAR(2) 加 CHECK 约束是标准做法比用 BIT 或 INT 可读性更好。时间字段统一用 DATETIME 而不是 DATE 或 TIME是因为考勤需要精确到时分秒这个选择是对的。3. 建库建表实操从 CREATE DATABASE 到六张表的完整脚本3.1 创建数据库与文件组参数文档给出的建库语句指定了数据文件和日志文件的逻辑名、物理路径、初始大小和增长方式。数据文件 worker_data 初始 3MB每次增长 1MB日志文件 worker_LOG 初始 1MB最大 50MB每次增长 10%。这个配置对课程设计来说够用但有几个参数在实际部署时需要调整。初始大小 3MB 偏小如果考勤数据每天几千条很快就要频繁增长建议改成 50MB 起步。日志文件最大 50MB 在批量导入历史考勤数据时可能不够我一般会设成 200MB 或者不设上限只设增长比例。文件增长方式用百分比10%在文件变大后会导致单次增长过大常见做法是改成固定大小增长比如每次 10MB。CREATE DATABASE worker ON ( NAME worker_data, FILENAME f:\worker.mdf, SIZE 3, FILEGROWTH 1 ) LOG ON ( NAME worker_LOG, FILENAME C:\worker_log.ldf, SIZE 1, MAXSIZE 50, FILEGROWTH 10% )这段代码里NAME 是逻辑文件名后续备份恢复时用得到FILENAME 是物理路径必须确保 SQL Server 服务账号对该路径有写权限否则建库直接报错。SIZE 单位是 MBFILEGROWTH 如果不带单位默认是 MB带 % 就是按当前大小的百分比增长。MAXSIZE 只限制日志文件数据文件没设上限生产环境建议两个都设。3.2 六张表的建表语句与约束设计文档给出了六张表的完整建表语句。职工表用 W_id 做单列主键姓名非空性别加 CHECK 约束年龄非空职称非空。出勤记录表用 W_id 和 w_num 做复合主键上下班时间允许空缺勤记录字段类型是 DATETIME 但实际存的是文本描述这里文档里写的是 datetime我建议改成 VARCHAR 存“迟到”“早退”“旷工”这类文字。出差、加班、请假三张表结构类似都是复合主键加时间字段加统计天数字段。月统计表用 w_id 做单列主键四个统计字段中出勤月统计非空其余允许空。CREATE TABLE worker ( W_id CHAR(4) CONSTRAINT worker_Prim PRIMARY KEY, w_name CHAR(6) NOT NULL, SEX CHAR(2) CONSTRAINT SEX_Chk CHECK(SEX男 OR SEX女) NOT NULL, AGE INT NOT NULL, w_drgee VARCHAR(4) NOT NULL ) CREATE TABLE work_note ( W_id CHAR(4), w_num INT, CONSTRAINT work_note_Prim PRIMARY KEY(W_id, w_num), work_tim DATETIME, end_tim DATETIME, work_note DATETIME ) CREATE TABLE out_note ( W_id CHAR(4), out_num INT, CONSTRAINT out_note_Prim PRIMARY KEY(W_id, out_num), out_tim DATETIME, back_tim DATETIME, out_days INT ) CREATE TABLE over_note ( W_id CHAR(4), over_num INT, CONSTRAINT over_note_Prim PRIMARY KEY(W_id, over_num), over_tim DATETIME, overend_tim DATETIME, over_days INT ) CREATE TABLE off_note ( W_id CHAR(4), off_num INT, CONSTRAINT off_note_Prim PRIMARY KEY(W_id, off_num), off_tim DATETIME, offend_tim DATETIME, off_days INT ) CREATE TABLE mounth_note ( w_id CHAR(6) CONSTRAINT mounth_Prim PRIMARY KEY, work_note INT NOT NULL, out_note INT, over_note INT, off_note INT )这里有几个参数需要说明。职工表的 W_id 用 CHAR(4)月统计表的 w_id 用 CHAR(6)两个表关联时会发生隐式类型转换虽然 SQL Server 能处理但会影响索引使用效率。我一般会统一成 CHAR(4) 或者都用 VARCHAR(10)。出勤记录表的 work_note 字段类型是 DATETIME但实际业务里这个字段存的是缺勤原因描述用 DATETIME 存文字会报错应该改成 VARCHAR(50)。出差、加班、请假三张表的统计天数字段用 INT如果请假是按小时算的这个字段就得改成 DECIMAL(5,1)。月统计表的四个统计字段用 INT如果一个月内出勤天数超过 255 天不可能或者加班时长按分钟统计这个类型就不够用实际项目里我一般用 INT 存天数、用 DECIMAL 存小时数。3.3 索引创建与执行计划验证文档在物理结构设计部分给出了在 mounth_note 表的 w_id 上创建唯一索引的语句。这个索引的作用是加速按员工编号查询月统计记录同时保证一个员工在月统计表里只有一条记录。创建索引的语法是标准的 CREATE INDEX后面跟 ON 表名(列名)然后用 sp_helpIndex 查看索引信息。CREATE INDEX M1 ON mounth_note(w_id) GO EXEC sp_helpIndex mounth_note这段代码里M1 是索引名mounth_note 是表名w_id 是列名。GO 是批处理分隔符不是 SQL 语句的一部分。sp_helpIndex 是系统存储过程用来查看指定表的索引信息输出包括索引名、索引描述和索引键列。执行完建索引语句后可以用 SET SHOWPLAN_ALL ON 或者直接在 SSMS 里看执行计划确认查询月统计时走了索引查找而不是全表扫描。如果表里数据量很小SQL Server 可能仍然选择全表扫描这是正常的不代表索引没建成功。4. 存储过程与触发器考勤统计自动化的核心逻辑4.1 插入出勤记录的存储过程文档给出的存储过程 insert_in 接收五个参数职工编号、出勤编号、上班时间、下班时间、缺勤记录然后插入到 work_note 表。调用时用 EXEC 传入具体参数值最后用 SELECT 查询验证插入结果。这个存储过程的价值在于把插入逻辑封装起来应用程序只需要调用存储过程名和参数不需要拼 SQL 语句减少了 SQL 注入的风险也方便后续修改插入逻辑时不用改应用代码。CREATE PROCEDURE insert_in ( W_id CHAR(4), w_num INT, work_tim DATETIME, end_tim DATETIME, work_note DATETIME ) AS INSERT INTO work_note VALUES(W_id, w_num, work_tim, end_tim, work_note) GO EXEC insert_in W_id0001, w_num1, work_tim2010/11/1, end_tim2010/11/1, work_noteNULL GO SELECT * FROM work_note参数说明W_id 是职工编号类型 CHAR(4)必须和表定义一致w_num 是出勤编号类型 INTwork_tim 和 end_tim 是上下班时间类型 DATETIMEwork_note 是缺勤记录类型 DATETIME但前面说过这个字段实际应该存文本所以这里传 NULL 或者改成 VARCHAR 类型。调用时用 EXEC 存储过程名 参数名值 的格式多个参数用逗号分隔。执行完插入后用 SELECT 查询 work_note 表确认数据是否写入。如果插入失败常见原因是参数类型不匹配或者主键冲突同一员工同一出勤编号已存在。4.2 月统计触发器的工作机制文档创建了两个触发器mounth_insert 在 work_note 表插入数据后触发更新 mounth_note 表中对应员工的出勤月统计worker_insert 在 worker 表插入数据后触发向 mounth_note 表插入一条初始记录。这两个触发器配合使用实现了“新增员工时自动创建月统计记录新增出勤时自动更新月统计”的自动化逻辑。CREATE TRIGGER mounth_insert ON work_note FOR INSERT AS BEGIN IF UPDATE(w_id) UPDATE mounth_note SET work_note ( SELECT COUNT(work_tim) FROM work_note WHERE w_id (SELECT W_id FROM inserted) GROUP BY w_id ) WHERE w_id (SELECT W_id FROM inserted) END CREATE TRIGGER worker_insert ON worker FOR INSERT AS BEGIN DECLARE id CHAR(20) SELECT id W_id FROM inserted IF UPDATE(W_id) INSERT INTO mounth_note VALUES(id, 0, 0, 0, 0) ENDmounth_insert 触发器的逻辑是当 work_note 表有新记录插入时从 inserted 临时表里取出新记录的 W_id然后统计 work_note 表中该员工的所有出勤记录数更新到 mounth_note 表的 work_note 字段。这里有一个性能隐患如果一次插入多条出勤记录inserted 表里有多行但子查询只取了其中一行的 W_id会导致统计不准确。正确做法是用 JOIN 或者 GROUP BY 处理 inserted 表的多行情况。worker_insert 触发器的逻辑是当 worker 表有新员工插入时从 inserted 表取出 W_id向 mounth_note 表插入一条初始记录四个统计字段都设为 0。这里 id 声明为 CHAR(20)但 worker 表的 W_id 是 CHAR(4)mounth_note 表的 w_id 是 CHAR(6)类型不一致会导致插入时发生截断或补空格建议统一长度。4.3 视图与查询封装文档最后创建了一个视图 mywork把 worker 表和 mounth_note 表连接起来输出职工编号、姓名、性别、年龄、职称、出勤月统计、加班月统计、出差月统计、请假月统计。这个视图的作用是给应用程序提供一个统一的查询接口应用程序不需要知道底层表怎么连接直接查视图就能拿到员工基本信息和月度统计。CREATE VIEW mywork AS SELECT worker.W_id, w_name, SEX, AGE, w_drgee, work_note, over_note, out_note, off_note FROM worker INNER JOIN mounth_note ON worker.W_id mounth_note.w_id这个视图用的是 INNER JOIN意味着只有同时在 worker 表和 mounth_note 表里有记录的员工才会出现在视图结果里。如果某个员工在 worker 表里有记录但 mounth_note 表里没有比如触发器没生效这个员工就不会出现在视图里。实际项目里我一般会用 LEFT JOIN保证员工基本信息始终能查出来统计字段为空时显示 NULL 或 0。5. 避坑与排查这套课设代码里最容易翻车的五个地方5.1 触发器里 inserted 表多行导致统计错误现象批量插入出勤记录后月统计表的出勤天数只增加了 1而不是实际插入的条数。原因mounth_insert 触发器里的子查询SELECT COUNT(work_tim) FROM work_note WHERE w_id (SELECT W_id FROM inserted)只取了 inserted 表的第一行 W_id如果一次插入多条不同员工的记录只会统计第一个员工的数据。解决把触发器改成基于 inserted 表的集合操作用 JOIN 或者 GROUP BY 一次性处理所有受影响员工。CREATE TRIGGER mounth_insert ON work_note FOR INSERT AS BEGIN UPDATE mounth_note SET work_note ( SELECT COUNT(*) FROM work_note wn WHERE wn.w_id mounth_note.w_id ) WHERE w_id IN (SELECT W_id FROM inserted) END5.2 字段类型不一致导致隐式转换和索引失效现象查询月统计时明明建了索引执行计划却显示全表扫描。原因worker 表的 W_id 是 CHAR(4)mounth_note 表的 w_id 是 CHAR(6)连接时 SQL Server 需要把 CHAR(4) 转换成 CHAR(6) 再比较导致索引无法使用。解决统一两张表的员工编号字段类型和长度要么都用 CHAR(4)要么都用 VARCHAR(10)。如果已经建表了用 ALTER TABLE 修改字段类型但要注意修改前先删掉索引和约束。5.3 缺勤记录字段用 DATETIME 存文本导致插入失败现象调用 insert_in 存储过程时传入 work_note迟到报错“从字符串转换日期和/或时间时失败”。原因work_note 表的 work_note 字段定义是 DATETIME只能存日期时间格式不能存“迟到”“早退”这类文本。解决把 work_note 字段类型改成 VARCHAR(50)存储过程参数 work_note 也改成 VARCHAR(50)。如果已经建表了用 ALTER TABLE work_note ALTER COLUMN work_note VARCHAR(50)。5.4 建库时文件路径权限不足导致 CREATE DATABASE 失败现象执行 CREATE DATABASE 语句时报错“无法创建文件 f:\worker.mdf操作系统错误 5拒绝访问”。原因SQL Server 服务账号对 f:\ 盘没有写权限或者 f:\ 盘不存在。解决把数据文件和日志文件路径改成 SQL Server 默认的数据目录或者给服务账号授予目标目录的写权限。常见做法是先用 SELECT SERVERPROPERTY(InstanceDefaultDataPath) 查默认数据目录然后把 FILENAME 改成该目录下的路径。5.5 月统计表初始记录缺失导致视图查不到员工现象新增员工后查询 mywork 视图看不到这个员工。原因worker_insert 触发器没有生效或者触发器中向 mounth_note 插入记录时因为主键冲突失败比如该员工编号已存在。解决先检查 worker_insert 触发器是否存在且启用用 SELECT * FROM sys.triggers WHERE nameworker_insert 确认。然后检查 mounth_note 表里是否有该员工的记录如果没有手动插入一条初始记录。最后检查触发器的 id 变量长度是否和 mounth_note.w_id 一致不一致会导致插入的值被截断或补空格主键匹配不上。6. 从课设到可交付把六张表跑通并验证统计口径这套文档给的是骨架真正要交课设或者拿去做原型还得把统计口径跑通。我一般会按这个顺序验证先插员工再插出勤、请假、加班、出差记录然后查月统计表看数字对不对最后查 mywork 视图看连接结果。验证的时候用下面这组 SQL能一次性把六张表都过一遍。-- 插入员工 INSERT INTO worker VALUES(0001, 张三, 男, 28, 工程师) INSERT INTO worker VALUES(0002, 李四, 女, 32, 经理) -- 插入出勤记录 INSERT INTO work_note VALUES(0001, 1, 2024-01-02 09:00, 2024-01-02 18:00, NULL) INSERT INTO work_note VALUES(0001, 2, 2024-01-03 09:15, 2024-01-03 18:00, NULL) INSERT INTO work_note VALUES(0002, 1, 2024-01-02 08:50, 2024-01-02 17:30, NULL) -- 插入请假记录 INSERT INTO off_note VALUES(0001, 1, 2024-01-05 09:00, 2024-01-05 18:00, 1) -- 插入加班记录 INSERT INTO over_note VALUES(0002, 1, 2024-01-03 18:30, 2024-01-03 21:00, 1) -- 插入出差记录 INSERT INTO out_note VALUES(0001, 1, 2024-01-08 09:00, 2024-01-10 18:00, 3) -- 查看月统计 SELECT * FROM mounth_note -- 查看视图 SELECT * FROM mywork执行完这组语句后mounth_note 表里应该出现两条记录0001 的出勤统计是 2请假统计是 1出差统计是 30002 的出勤统计是 1加班统计是 1。如果数字不对先检查触发器是否生效再检查 inserted 表的多行处理逻辑。mywork 视图应该返回两条记录包含员工基本信息和统计字段。如果视图返回空检查 INNER JOIN 是否因为 mounth_note 表缺少对应记录而过滤掉了员工。有一个细节值得单独说文档里月统计表的 w_id 是 CHAR(6)而 worker 表的 W_id 是 CHAR(4)插入 0001 到 CHAR(6) 字段时 SQL Server 会自动补两个空格变成 0001 。查询的时候如果用 WHERE w_id0001SQL Server 会忽略尾部空格所以能查到但用 JOIN 连接时如果两边类型不一致执行计划可能不走索引。我一般会在建表时就把所有员工编号字段统一成 CHAR(4) 或者 VARCHAR(10)避免这种隐式转换。从那以后我每次拿到一套课设库表都强制先跑一遍“插员工→插业务记录→查统计→查视图”的完整链路确认触发器逻辑和字段类型没问题再往下做应用层。这套文档的 E-R 图和关系模式可以直接用但建表语句里的字段类型和触发器逻辑需要按上面说的几个点改一改。希望帮到你。本文还有配套的精品资源点击获取