因为要求对于教师和课程等等的对应关系没有说明,所以可以自由发挥,我能找到教师和课程之间是一对一关系的实现,但是因为我想要实现教师课程多对多的数据库,所以就自己发挥了。
当时做实验的时候,对数据的描述如下:
一名学生可以选修多门课程,一门课程可被多个学生选修,每门课程对应一个老师,每门课程有一个成绩,且选修课程名不能重复;一名教师可以任教多门课程,一门课程可由多个老师教授,每个老师所任教的每门课程有一个课程评价;一个老师可教多名学生。
E-R图如下:
用Excel做的表格如下:
这个实现的问题就在于每个学生选的课程,是需要教师号和课程号一起才能共同确定的,这种情况实验要求就会很麻烦(而且E-R图上是三角多对多感觉很难受)改进思路就是将多一个临时班级实体,一个临时班级对应一个教师和一个课程,这样就可以将学生对老师和学生对课程这两个多对多关系化简成临时班级对老师,临时班级对课程这两个一对多的关系。
接下来,正文开始。
有要求,可转化成如下数据间关系:
一名学生可以选修多门课程,一门课程可被多个学生选修,学生选修课程的实质是选临时班级。每个临时班级对应一门课程和一个老师,每门课程有一个成绩,且选修课程名不能重复;一名教师可以任教多门课程,一门课程可由多个老师教授。E-R图如下:
这里临时班级多了一个人数的属性主要是为了接下来统计人数方便。
这里可以先按照E-R图在excel上把表建出来,输一些用于插入数据时做参考和验证。
需要建立的东西如下(加粗为主码):
学生(学号,姓名,性别,生日,专业)
教师(职工号,姓名,性别)
课程(课程号,课程名,学分,开课学期)
临时班级(班级号,课程号,教师号,人数)
选课(学号,班级号,成绩)
未选修06-07(班级号,课程名,教师名)
学生不能选择课程号相同的课程。
查看指定学期的学生学分
各教师任课的学生人数
下面是实现过程:
建立选课模式
CREATESCHEMAselect_courses;建立实体表
--studenttableCREATETABLEstudents(stu_idINTPRIMARYKEY,nameVARCHAR(40),birth_dayDATE,sexVARCHAR(1),majorVARCHAR(40));--teachertableCREATETABLEteathers(tea_idINTPRIMARYKEY,nameVARCHAR(40),sexVARCHAR(1));--coursestableCREATETABLEcourses(course_idINTPRIMARYKEY,course_nameVARCHAR(40),creditINT,open_timeVARCHAR(20));--tempclasstableCREATETABLEclasses(class_idINTPRIMARYKEY,course_idINT,tea_idINT,numberINTDEFAULT0,FOREIGNKEY(course_id)REFERENCEScourses(course_id)ONDELETECASCADE,FOREIGNKEY(tea_id)REFERENCESteathers(tea_id)ONDELETECASCADE);建立多对多关系表
CREATETABLEselect_courses(stu_idINT,class_idINT,gradeINT,PRIMARYKEY(stu_id,class_id),FOREIGNKEY(stu_id)REFERENCESstudents(stu_id)ONDELETECASCADE,FOREIGNKEY(class_id)REFERENCESclasses(class_id)ONDELETECASCADE);插入除select_courses表以外的数据。这里要注意,在向classes表插入数据时,不要插入人数的数据。人数将会通过触发器,每当有人选课时(即向select_courses插入数据时),对应班级人数加一,删除同理。
CREATETRIGGERclass_number_insertAFTERINSERTONselect_coursesFOREACHROWBEGINIFNEW.class_idIN(SELECTclass_idFROMclasses)THENUPDATEclassesSETnumber=number+1WHEREclass_id=NEW.class_id;ENDIF;END;CREATETRIGGERclass_number_deleteAFTERDELETEONselect_coursesFOREACHROWBEGINIFOLD.class_idIN(SELECTclass_idFROMclasses)THENUPDATEclassesSETnumber=number-1WHEREclass_id=OLD.class_id;ENDIF;END;向select_courses表插入数据
INSERTINTOselect_coursesVALUES(101,6001,90);INSERTINTOselect_coursesVALUES(101,6003,87);INSERTINTOselect_coursesVALUES(101,6008,80);INSERTINTOselect_coursesVALUES(102,6001,75);INSERTINTOselect_coursesVALUES(102,6002,60);INSERTINTOselect_coursesVALUES(103,6001,93);INSERTINTOselect_coursesVALUES(103,6010,85);INSERTINTOselect_coursesVALUES(103,6008,70);INSERTINTOselect_coursesVALUES(104,6004,87);INSERTINTOselect_coursesVALUES(104,6007,85);INSERTINTOselect_coursesVALUES(104,6010,80);INSERTINTOselect_coursesVALUES(105,6006,90);建立触发器,实现学生不能选择课程号相同的课程。若选择学生选择已选的课程,会抛出coursewasselected的异常。
CREATETRIGGERnon_repetitionBEFOREINSERTONselect_coursesFOREACHROWBEGINIF(SELECTcourse_idFROMclassesWHERENEW.class_id=class_id)IN(SELECTclasses.course_idFROMselect_coursesJOINclassesONclasses.class_id=select_courses.class_idWHEREstu_id=NEW.stu_id)THENSIGNALSQLSTATE'HX000'SETMESSAGE_TEXT='coursewasselected';ENDIF;END;可以尝试插入一个错误数据,看看结果是否正确。6002班级的课程为3001,而101学生已选的6001班级也是教3001课程的,所以理论上这个数据不应该被插入。
INSERTINTOselect_coursesVALUES(101,6002,90);创建视图,查询2006-2007学年没有被选修的课程这里“未选修”对应到表上就是,课程人数为0。2006-2007学年即2006-2007-1和2006-2007-2两个学期。
CREATEVIEWnot_selected_2006_2007ASSELECTclass_id,course_name,nameFROMclassesJOINcoursesconclasses.course_id=c.course_idJOINteatherstonclasses.tea_id=t.tea_idWHEREnumber=0ANDopen_timein('2006-2007-1','2006-2007-2');创建存储过程,查看指定学期的学生学分
CREATEPROCEDUREget_total_credit(INtermVARCHAR(20))BEGINSELECTstudents.stu_id,students.name,SUM(courses.credit)FROMselect_coursesJOINclassesONclasses.class_id=select_courses.class_idJOINstudentsONselect_courses.stu_id=students.stu_idJOINcoursesONclasses.course_id=courses.course_idWHEREcourses.open_time=termGROUPBYstudents.stu_id,name;END;创建存储过程,各教师任课的学生人数
CREATEPROCEDUREnum_of_students()BEGINSELECTt.name,c.course_name,SUM(number)num_of_stuFROMclassesJOINcoursesconclasses.course_id=c.course_idJOINteatherstonclasses.tea_id=t.tea_idGROUPBYc.course_id,t.tea_id;END;这里会发现,结果和classes表一样,只有当你允许一个老师开好几个班上同一门课时(即班级号不同但教师号和课程号不同),才会不同。
至此,数据库建立完毕。
这里的设计和原来相比,取巧的地方在于,多加了一个临时班级实体,不仅将学生对课程、学生对老师、老师对课程的三角多对多关系,转化成课程对班级、老师对班级的一对多关系和学生对班级的多对多关系;而且临时班级实体中加入的班级人数属性,可以被查询没有被选修的课程、统计教师任课的学生人数的实现加以利用,代码更简洁。