☰
Oracle数据库课程设计:学生考勤管理系统完整落地指南
2026/10/19 7:32:26 网站建设 项目流程

简介:这份Oracle数据库课程设计资料面向学习数据库管理与开发的学生及IT从业者,以“学生考勤系统”为完整案例,帮助读者掌握从需求分析到物理实现的数据库设计全流程。资源包内含1个doc文档,约227KB,为辽宁工程技术大学软件学院的课程设计报告,目录涵盖背景分析、需求分析、E-R模型、数据字典、逻辑结构设计、表空间与建表、心得体会等章节。报告详细划分了请假、考勤、后台管理三大模块,并针对学生、任课老师、班主任、院系领导、学校领导、系统管理员六类角色梳理用户需求,同时给出表空间创建、建表语句及其他数据库对象的设计示例。已有965人学习,适合作为课程设计参考模板,也可用于理解Oracle中SQL查询、存储过程、触发器及权限管理等知识点的实际应用,帮助读者快速搭建考勤系统的设计框架并完成报告撰写。

1. 学生考勤管理系统:从点名痛点到 Oracle 数据库落地的完整设计

高校里最让任课老师头疼的事,不是备课,而是每节课花五分钟点名,期末还要手动汇总一学期的出勤记录。更麻烦的是请假流程:学生找班主任签字,班主任要找院系领导审批,一张假条跑三个办公室,最后任课老师还不知道这个学生到底请没请假。这套学生考勤管理系统要解决的,就是把请假审批、出勤记录、多角色查询这三件事全部收进一个 Oracle 数据库驱动的信息系统里。它适合正在做数据库课程设计的学生,也适合需要一套完整 Oracle 设计方案做参考的开发者。核心思路不复杂:用六类用户角色撑起权限体系,用三张核心业务表(请假、考勤、课表)串起数据流,用存储过程、视图、触发器把业务逻辑下沉到数据库端。

2. 需求分析与角色建模:六类用户到底各自要什么

2.1 从真实场景反推功能边界

很多课程设计翻车,不是因为 SQL 写得不好,而是需求阶段就没想清楚“谁用这个系统、用来干什么”。这套系统的用户不是一类人,是六类:学生、任课老师、班主任、院系领导、学校领导、系统管理员。每一类人对“考勤”这件事的关注点完全不同。

学生的核心诉求有两个:一是在线请假,并且能随时看到请假走到哪一步了——班主任批了没有、院系领导批了没有;二是查看自己整个学期每门课的出勤记录,包括请假几次、旷课几次。任课老师要的是:每节课后能快速录入出勤状态,系统自动结合请假数据判断某个学生是“请假”还是“旷课”,而不是手动去翻假条。班主任需要审批本班学生的请假申请,同时查看全班所有课程的出勤统计。院系领导审批超过三天的长假,查看本院系学生的出勤情况。学校领导只看全校层面的汇总数据。系统管理员负责维护院系、专业、班级、课程、课表、用户这些基础数据。

这里有一个容易被忽略的设计点:请假和考勤不是两个独立模块,它们之间有数据依赖。任课老师录入出勤时,系统需要自动查询该学生该时段是否有已批准的请假记录,如果有,出勤状态自动标记为“请假”而非“旷课”。这个联动关系如果不在需求阶段理清,后面写存储过程时会非常被动。

2.2 功能模块划分与数据流

系统划分为三大功能模块:请假系统模块、考勤系统模块、后台管理模块。请假模块涉及学生、班主任、院系领导三类用户,核心是一张请假信息表在三个角色之间的状态流转。考勤模块涉及全部六类用户,但权限范围不同:学生只看自己,任课老师管自己所教班级,班主任看本班,院系领导看本院系,学校领导看全校。后台管理模块只涉及系统管理员,负责所有基础数据的增删改查。

数据流的主线是这样的:系统管理员先录入院系、专业、班级、课程、教师、课表等基础数据;学生在系统中提交请假申请,写入请假信息表,初始审批状态为“等待审批”;班主任登录后看到待审批列表,审批后更新班主任审批状态字段;如果请假天数超过三天,系统自动将记录推给院系领导审批,更新院系领导审批状态字段;任课老师录入出勤时,系统根据请假信息表中已批准的记录,自动判定出勤状态。

注意:请假审批的状态字段设计要统一。原文中审批状态用 0/1/2 表示等待审批、同意、不同意,这个约定要在建表时就写进 CHECK 约束,否则后期数据混乱。

3. 数据库设计:从 E-R 模型到十二张表的逻辑结构

3.1 E-R 模型与实体关系梳理

E-R 模型是整个数据库设计的地基。这套系统的实体包括:学生、教师、班主任、院系领导、学校领导、系统管理员、院系、专业、班级、课程、请假条、考勤记录。实体之间的关系用一句话概括:一个院系有多个专业,一个专业有多个班级,一个班级有多个学生,一个班级有一个班主任,一个院系有多个教师,教师通过课程表与班级建立授课关系,学生通过请假条发起请假流程,任课老师通过考勤记录表录入出勤。

这里有一个设计决策值得展开说:班主任和院系领导是单独建表还是复用教师表?原文选择了单独建表(classteacher 和 collegeleader),原因是班主任有“所属专业”这个属性,院系领导有“职称”和“所属学院”属性,与普通教师表的字段不完全一致。这个选择在课程设计阶段是合理的,因为表结构更清晰,查询时不需要用角色字段过滤。代价是数据冗余——如果一个人既是教师又是班主任,需要在两张表里各存一条记录。通常的做法是:如果系统规模不大、角色边界清晰,单独建表更直观;如果角色可能重叠,用一张人员表加角色关联表更灵活。

3.2 十二张表的字段设计与约束

逻辑结构设计的核心任务是把 E-R 模型转成具体的表定义。这套系统一共十二张表,按功能分三组:

基础数据表:院系表(faculty)、专业表(major)、班级表(classes)、课程表(course)、教师表(teacher)、班主任表(classteacher)、院系领导表(collegeleader)、学校领导表(schoolleader)、系统管理员表(admin)。

业务表:请假信息表(qingjia)、学生上课出勤记录表(kaoqin_record)。

学生表(student)横跨基础数据和业务查询,既存储学生基本信息,也作为考勤和请假的外键关联对象。

关键字段设计上,有几点需要特别注意。请假信息表的主键用 number 类型的 id,而不是用学号加时间的组合键,原因是同一学生同一时段可能提交多条请假记录(比如先请了三天,后来续假),用自增 id 更稳妥。考勤记录表的主键用 char(13) 的 kaoqin_id,这个长度足够容纳“日期+课程号+学号”的组合编码。审批状态字段用 char(10) 存储,原文备注中约定 0 为等待审批、1 为同意、2 为不同意,建议在建表时加 CHECK 约束限定取值范围。

外键约束方面,学生表的 stu_class 引用班级表的 class_no,stu_major 引用专业表的 major_id,stu_faculty 引用院系表的 faculty_id。请假信息表的 stu_no 引用学生表的 stu_no,class_tea_id 引用班主任表的 classtea_no,coll_leader_id 引用院系领导表的 collegeleader_no。考勤记录表的 stu_number 引用学生表,teacher_no 引用教师表,course_no 引用课程表。这些外键保证了数据的参照完整性,但也意味着插入数据的顺序不能乱——必须先有院系、专业、班级,才能插学生;先有教师和课程,才能插考勤记录。

3.3 表空间设计与物理存储

原文中创建了一个名为 linpeng_data 的字典管理表空间,数据文件放在 /u01/oracle/oradata/tab01.dbf,初始大小 100M,默认存储参数为 initial 512K、next 128K、minextents 2、maxextents 999、pctincrease 0。这个配置在课程设计场景下是够用的,但有几个参数值得说明。

initial 512K 表示第一段分配 512K 空间,next 128K 表示后续每次扩展 128K。minextents 2 表示每个段至少分配两个区,maxextents 999 是最大区数。pctincrease 0 表示后续区的大小不按百分比递增,保持固定大小。这套参数适合数据量不大、增长平稳的教学演示系统。如果实际部署,通常会把 initial 和 next 设得更大一些,减少区分配次数。

所有业务表都指定了 tablespace linpeng_data,这样做的目的是把用户数据和系统数据分开存储,便于管理和备份。建表时如果不指定表空间,表会默认建在 SYSTEM 表空间里,这是应该避免的。

4. 核心数据库对象实现:存储过程、视图与触发器

4.1 建表语句与约束实现

建表不是把字段名和类型敲进去就完事,约束的设计直接决定了数据质量。以下面这张请假信息表为例:

CREATE TABLE qingjia ( id NUMBER PRIMARY KEY, class_id CHAR(10) FOREIGN KEY REFERENCES classes(class_no), stu_no CHAR(10) FOREIGN KEY REFERENCES student(stu_no), leave_reason VARCHAR2(200) NOT NULL, start_time DATE NOT NULL, end_time DATE NOT NULL, day_number NUMBER NOT NULL, qingjia_time DATE NOT NULL, class_tea_id CHAR(5) FOREIGN KEY REFERENCES classteacher(classtea_no), class_tea_sp_status CHAR(10) CHECK (class_tea_sp_status IN ('0','1','2')), class_tea_sp_time DATE, coll_leader_sp_status CHAR(10) CHECK (coll_leader_sp_status IN ('0','1','2')), coll_leader_id CHAR(5) FOREIGN KEY REFERENCES collegeleader(collegeleader_no), coll_leader_sp_time DATE ) TABLESPACE linpeng_data;

这段建表语句有几个设计点值得展开。第一,leave_reason 设为 NOT NULL,因为请假原因必须填写,否则审批人无法判断是否批准。第二,start_time 和 end_time 用 DATE 类型,Oracle 的 DATE 类型包含日期和时间,精度到秒,对于请假场景足够用。第三,两个审批状态字段都加了 CHECK 约束,限定只能是 ‘0’、‘1’、‘2’,防止写入非法状态值。第四,班主任审批时间和院系领导审批时间允许为空,因为提交请假时还没有审批,这两个字段在审批动作发生时才写入。

原文中部分建表语句使用了datetime类型,这在 Oracle 中并不存在,Oracle 的日期时间类型是 DATE 或 TIMESTAMP。这是一个常见的踩坑点,后面避坑章节会展开。

4.2 存储过程:统计学生某门课的缺勤次数

存储过程的价值在于把计算逻辑封装在数据库端,应用程序只需要调用,不需要把数据拉到应用层再计算。下面这个存储过程用于统计某个学生在某门课程中的缺勤次数:

CREATE OR REPLACE PROCEDURE getMessage( stu_no IN VARCHAR2, course_no IN VARCHAR2, total_times OUT NUMBER ) AS absence_times NUMBER; BEGIN SELECT COUNT(*) INTO absence_times FROM kaoqin_record WHERE stu_number = stu_no AND course_no = course_no AND stu_status = '旷课'; total_times := absence_times; END;

参数说明:stu_no 是输入参数,学生学号;course_no 是输入参数,课程编号;total_times 是输出参数,返回缺勤次数。过程内部的查询条件是三个字段的联合过滤——学号匹配、课程号匹配、出勤状态为“旷课”。调用方式是在 PL/SQL 块中声明一个变量接收输出值,或者从应用程序中通过 CallableStatement 调用。

这个存储过程有一个容易忽略的细节:原文中统计的是所有考勤记录数,没有过滤出勤状态。如果学生正常出勤的记录也被计入,统计结果就没有意义。通常的做法是加上AND stu_status = '旷课'条件,只统计缺勤记录。

4.3 视图:按院系隔离考勤数据

视图的核心作用是数据隔离和权限控制。院系领导只能看本院系学生的考勤信息,学校领导可以看全校的。用视图来实现这个隔离,比在应用层写 WHERE 条件更安全,因为权限控制下沉到了数据库层。

CREATE VIEW rjxy AS SELECT k.kaoqin_id, k.sk_time, k.stu_number, k.stu_status, k.teacher_no, k.course_no FROM kaoqin_record k, student s WHERE s.stu_no = k.stu_number AND s.stu_faculty = 5;

这个视图的逻辑是:把考勤记录表和学生表做连接,筛选出 stu_faculty 等于 5 的记录。假设 5 是软件学院的院系编号,那么软件学院的院系领导查询这个视图时,只能看到本院系学生的考勤数据。其他院系的领导需要各自的视图,或者用带参数的存储过程来动态生成查询。

视图的另一个好处是简化查询。应用程序不需要知道 kaoqin_record 和 student 两张表的连接关系,直接查视图就行。如果后续表结构有调整,只需要修改视图定义,应用程序代码不用动。

4.4 触发器:缺勤超限自动预警

触发器适合处理“当某件事发生时,自动做另一件事”的场景。这套系统里最典型的触发器需求是:当任课老师录入一条考勤记录后,如果该学生该课程的累计缺勤次数达到阈值,自动给出预警。

CREATE OR REPLACE TRIGGER alertMessage AFTER INSERT ON kaoqin_record FOR EACH ROW DECLARE current_times NUMBER; BEGIN SELECT COUNT(*) INTO current_times FROM kaoqin_record WHERE stu_number = :new.stu_number AND course_no = :new.course_no AND stu_status = '旷课'; IF current_times >= 3 THEN DBMS_OUTPUT.PUT_LINE( '学号为:' || :new.stu_number || '的学生该门课程被取消考试资格!' ); END IF; END;

触发时机是 AFTER INSERT,即考勤记录插入成功后触发。FOR EACH ROW 表示行级触发器,每插入一行执行一次。:new.stu_number 和 :new.course_no 引用的是刚插入的那条记录的学生学号和课程号。触发器内部重新统计该学生该课程的旷课总次数,如果达到 3 次,通过 DBMS_OUTPUT 输出预警信息。

这里有一个实际使用中的限制:DBMS_OUTPUT.PUT_LINE 的输出只在 SQL*Plus 或支持 DBMS_OUTPUT 的工具中可见,应用程序端不一定能收到。更稳妥的做法是把预警信息写入一张独立的预警表,应用程序定时轮询这张表。但在课程设计阶段,用 DBMS_OUTPUT 演示触发器逻辑是够用的。

5. 避坑与常见问题:那些年踩过的 Oracle 坑

5.1 数据类型不匹配:datetime 不是 Oracle 的类型

现象:建表语句执行报错,提示“ORA-00902: invalid datatype”。

原因:原文中多处使用了datetime作为字段类型,但 Oracle 数据库没有 datetime 这个类型。Oracle 的日期时间类型是 DATE(精度到秒)和 TIMESTAMP(精度到小数秒)。MySQL 和 SQL Server 有 datetime 类型,容易混淆。

解决:把所有 datetime 替换为 DATE。如果课程设计要求记录更精确的时间,用 TIMESTAMP。建表前先确认目标数据库的类型体系,不要凭记忆写。

5.2 外键引用顺序错误:先建子表后建父表

现象:执行建表语句时报“ORA-00942: table or view does not exist”。

原因:建表顺序不对。比如 student 表引用了 classes 表的外键,如果先建 student 再建 classes,Oracle 找不到被引用的表。同理,kaoqin_record 引用了 student、teacher、course 三张表,必须在这三张表建好之后才能建。

解决:按依赖关系排序建表。先建无外键的基础表:faculty、major、classteacher、collegeleader、schoolleader、admin、course。再建依赖基础表的表:classes(依赖 classteacher)、teacher(依赖 faculty)、student(依赖 classes、major、faculty)。最后建业务表:qingjia(依赖 classes、student、classteacher、collegeleader)、kaoqin_record(依赖 student、teacher、course)。

5.3 存储过程参数名与字段名冲突

现象:存储过程编译通过,但执行结果不对,或者报“ORA-01422: exact fetch returns more than requested number of rows”。

原因:存储过程的输入参数名和 SQL 语句中的字段名相同。比如参数叫 stu_no,查询条件写WHERE stu_number = stu_no,Oracle 会优先把 stu_no 解析为字段名而不是参数名,导致条件变成stu_number = stu_number,永远为真。

解决:参数命名加前缀,比如p_stu_no,或者在 SQL 中用存储过程名限定参数:WHERE stu_number = getMessage.stu_no。我一般习惯参数加p_前缀,变量加v_前缀,一眼就能区分。

5.4 触发器中的 DBMS_OUTPUT 不输出

现象:触发器创建成功,插入数据也成功,但看不到 DBMS_OUTPUT 的输出信息。

原因:DBMS_OUTPUT 需要先执行SET SERVEROUTPUT ON才能显示输出。在 SQL*Plus 中默认是关闭的。另外,如果通过应用程序连接数据库,DBMS_OUTPUT 的内容不会自动传到应用端。

解决:在 SQL*Plus 中先执行SET SERVEROUTPUT ON。如果需要在应用端获取预警信息,把触发器改为写入独立的预警表,应用程序查询预警表获取信息。

5.5 表空间路径不存在导致建表空间失败

现象:执行 CREATE TABLESPACE 时报“ORA-01119: error in creating database file”或“ORA-27040: file create error”。

原因:数据文件路径/u01/oracle/oradata/tab01.dbf在目标机器上不存在,或者 Oracle 进程没有该目录的写权限。

解决:先用mkdir -p /u01/oracle/oradata创建目录,确认 Oracle 用户对该目录有写权限。或者直接使用 Oracle 的默认数据文件目录,通过SELECT name FROM v$datafile;查看现有数据文件路径,把新表空间的数据文件放在同一目录下。

6. 验收与答辩:怎么证明这套设计真的能跑

6.1 验收清单与测试用例

课程设计的验收不是看报告写了多少页,而是看数据库能不能跑通完整的业务流程。我一般会准备一套测试用例,按业务流程顺序执行,每一步都有明确的预期结果。

测试步骤操作预期结果
1插入院系、专业、班级数据三张表各有对应记录
2插入学生、教师、班主任数据外键关联正确,无报错
3插入课程和课表数据课程与班级的授课关系建立
4学生提交请假申请qingjia 表新增记录,审批状态为 0
5班主任审批通过class_tea_sp_status 更新为 1
6请假天数超过 3 天,院系领导审批coll_leader_sp_status 更新为 1
7任课老师录入出勤记录kaoqin_record 表新增记录
8查询某学生某课程出勤统计调用 getMessage 存储过程,返回正确缺勤次数
9查询院系视图只返回本院系学生的考勤记录
10插入第 3 条旷课记录触发器输出预警信息

这套测试用例覆盖了建表、外键、存储过程、视图、触发器五个核心知识点。答辩时按这个顺序演示,每一步都能对应到设计文档中的某个模块,逻辑清晰。

6.2 答辩时怎么讲清楚设计思路

答辩最怕的是“做了什么说不清”。我的经验是:不要照着报告念,用一条数据流把整个系统串起来。比如这样讲:“系统管理员先录入基础数据,这是第一步。然后学生提交请假,数据进入请假表,状态是等待审批。班主任登录看到待审批列表,审批后状态变成同意。如果请假超过三天,院系领导还要再审批一次。任课老师录入出勤时,系统自动查请假表,已经批准的就标记为请假,没批准的就标记为旷课。最后,每个角色看到的考勤数据范围不同,这是通过视图来控制的。”

这段话把六类用户、三张核心表、存储过程、视图、触发器全部串起来了,评委一听就知道你真的理解了自己的设计,而不是拼凑出来的。

提示:答辩前把建表语句、存储过程、视图、触发器的创建脚本整理成一个 .sql 文件,按顺序排列,现场演示时直接执行,避免手忙脚乱。

6.3 从课程设计到实际项目的差距

课程设计的表结构通常够用,但离实际部署还有距离。几个常见的差距:没有考虑并发控制,多个任课老师同时录入考勤时可能出现数据冲突;没有索引优化,数据量大了之后查询会变慢;没有备份恢复策略,数据丢了就没了。如果课程设计要拿高分,可以在报告里加一节“性能优化与扩展方向”,提一下在 kaoqin_record 表的 stu_number 和 course_no 上建复合索引,在 qingjia 表的 stu_no 和审批状态上建索引,这些细节能让评委看到你考虑了实际场景。

从那以后我每次做数据库设计,都会先把建表脚本按依赖顺序排好,建完表立刻插入测试数据跑一遍完整流程,确认外键、约束、存储过程、触发器都能正常工作,再开始写报告。这个习惯帮我省了很多返工的时间。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询