您的当前位置:首页正文

计科09-数据库技术实践-第三部分

来源:华佗健康网


实 验 报 告

课程名称 数据库技术实践 实验项目 存储过程、触发器、用户自定义函数与游标 实验仪器 SQL Server 2008

系 别____计算机科学与技术系 _ 专 业____计算机科学与技术____ 班级/学号_______________________

学生姓名 _______________________ 实验日期 ___ _______ 成 绩 _______________________

指导教师 ___ _______ _______

[在内容说明部分请总体说明在本部分实践过程中,具体都完成了哪些内容]

一.内容说明

[请按照下面练习题的要求,完成各项内容,并说明每个题目完成的情况,是否存在问题,如何解决等]

二. 实验步骤与内容

如无特别说明,以下各题均利用之前建立的Students数据库以及Student、Course和SC表实现。

1.创建满足下述要求的存储过程,并查看存储过程的执行结果。 (1) 查询每个学生的修课总学分,要求列出学生学号及总学分。

create proc SumCredit as

select sno 学号,sum(credit) 总学分 from sc join course c on sc.cno=c.cno

group by sno go

exec SumCredit

(2) 查询学生的学号、姓名、修的课程号、课程名、课程学分,将学生所在

系作为输入参数,默认值为“计算机系”。执行此存储过程,并分别指定一些不同的输入参数值,查看执行结果。 create proc StudentInformation

@dept varchar(50)='计算机系',@sname char(50) as

select sc.sno 学号,sname 姓名,sc.cno 课程号,cname 课程名,credit 学分

from Student s join SC on s.Sno=sc.Sno join Course c on c.Cno = SC.Cno

where dept = @dept and Sname = @sname go

exec StudentInformation '信息管理系','吴宾'

exec StudentInformation @sname='李勇'

(3) 查询指定系的男生人数,其中系为输入参数,人数为输出参数。

create proc Man_Num

@dept varchar(50),@rs int output as

select @rs=COUNT(*) from Student where Dept=@dept and Sex='男' go

declare @rs int

exec Man_Num '信息管理系',@rs output select @rs as 人数

(4) 查询考试平均成绩超过指定分值的学生学号和平均成绩。

create proc AvgGrade @grade int as

select sno,AVG(grade) as '平均成绩' from SC group by Sno

having AVG(grade)>@grade go

exec AvgGrade 60

(5) 查询查询指定系的学生中,选课门数最多的学生的选课门数和平均成绩,

要求系为输入参数,选课门数和平均成绩用输出参数返回。 create proc Choose_Course

@dept varchar(50),@rs int output,@avg int output as

select top 1 @rs=COUNT(*) ,@avg=avg(grade) from Student s join SC on s.Sno=sc.Sno join Course c on c.Cno = SC.Cno where dept=@dept group by sc.Sno go

declare @rs int,@avg int

exec Choose_Course '信息管理系',@rs output,@avg output select @rs as 选课门数,@avg as 平均成绩

(6) 删除指定学生的修课记录,其中学号为输入参数。 create proc Del_Course @sno char(50) as

delete from SC where Sno=@sno go

exec Del_Course '0831102'

(7) 修改指定课程的开课学期。输入参数为:课程号和修改后的开课学期,

开课学期的默认值为2。如果指定的开课学期不在1~8范围内,则不进行修改。

2.利用SSMS工具查看在students数据库中创建的全部存储过程。 Students=>可编程性=> 存储过程

3.修改第1题(1)的存储过程,使之能够查询指定系中,每个学生选课总门数、总学分和考试平均成绩。 alter proc SumCredit @dept nvarchar(20) as select COUNT(SC.Cno) 总门数,sum(credit) 总学分,AVG(Grade) 平均成绩 from student s left join sc on s.sno=sc.sno left join course c on sc.cno=c.cno where dept = @dept

group by sc.Sno go exec SumCredit '信息管理系'

4.创建满足下述要求的触发器(前触发器、后触发器均可),并验证触发器执行情况。

(1) 限制每个学期开设的课程总学分在20~30范围内。

alter trigger TR_SumGrade on course after insert as

declare @s int,@x int,@y int

set @s=(select sum(Credit) from course where semester in(select semester from inserted)) if(20<@s and @s<30) begin

print '课程总学分没有超出范围' print @s end else begin

print'课程总学分超出范围' print's=' print @s rollback end

insert into course values('C010','汇编语言',200,1)

(2) 限制每个学生每学期选课门数不能超过5门(设只针对插入操作)。

ALTER trigger TR_MEN on sc after insert as

declare @x int

set @x=(select count(*) from sc join course c on sc.cno=c.cno

where semester in(select semester from course where cno in(select cno from inserted))and sc.sno in(select sno from inserted)) if(@x>5) begin

select * from sc join course c on sc.cno=c.cno select *from inserted print @x

print '选课门数超过门' rollback end

5.在Students数据库建立如下所示的工作表和职工表 CREATE TABLE 工作表(

工作号 CHAR(8) PRIMARY KEY, 最低工资 SMALLINT, 最高工资 SMALLINT ) CREATE TABLE 职工表(

职工号 CHAR(7) PRIMARY KEY, 职工名 CHAR(10) NOT NULL,

工作号 CHAR(8) REFERENCES 工作表(工作号), 基本工资 SMALLINT,

浮动工资 SMALLINT )

利用这两张表建立满足如下要求的触发器。

(1) 限制职工的基本工资和浮动工资之和必须大于等于2000。

create trigger TR_Salary

on 职工表 after insert,update as

declare @x SMALLINT,@y SMALLINT,@z SMALLINT

set @x=(select 基本工资 from 职工表 where 职工号 in(select 职工号 from inserted))

set @y=(select 浮动工资 from 职工表 where 职工号 in(select 职工号 from inserted)) set @z=@x+@y if(@z>=2000) begin

print'操作符合要求' end else begin print @x print @y print @z

print'请注意,职工的基本工资和浮动工资之和小于' select * from 职工表 select * from inserted rollback end

insert into 工作表 values('G001',10000,1000) insert into 职工表values('Z001','张三','G001',1000,100)

(2) 限制工作表中最高工资不能低于最低工资的1.5倍。

create trigger TR_Salary1

on 工作表 after insert,update as

declare @x SMALLINT,@y SMALLINT,@z float

set @x=(select 最低工资 from 工作表 where 工作号 in(select 工作号 from inserted))

set @y=(select 最高工资 from 工作表 where 工作号 in(select 工作号 from inserted)) set @z=@y/@x if(@z>=1.5) begin

print'操作符合要求' end else begin print @x print @y print @z

select * from 工作表 select * from inserted

print '请注意,最高工资低于最低工资的.5倍' rollback end

insert into 工作表 values('G002',1000,1000)

(3) 限制不能删除基本工资低于1500的职工。

alter trigger TR_Salary2 on 职工表 after delete as

if exists(select * from 职工表 where 基本工资<1500) begin

print'操作符合要求' end else begin

print'不能删除基本工资低于的职工' select * from 职工表 select * from deleted rollback end

6.创建满足下述要求的用户自定义标量函数。

(1) 查询指定学生已经得到的修课总学分(考试及格的课程才能拿到学分),

学号为输入参数,总学分为函数返回结果。并写出利用此函数查询9512101学生的姓名、所修的课程名、课程学分、考试成绩以及拿到的总学分的SQL语句。

create function dbo.Sum_Credit(@sno char(7)) returns int as begin

declare @sum int set @sum=(select sum(credit) from sc join course c on sc.cno=c.cno where sc.sno=@sno and grade>=60) return @sum end

select sname 姓名,sc.cno 课程名,credit 课程学分,grade 考试成绩,dbo.Sum_Credit(sc.sno) as 总学分 from sc join course c on sc.cno=c.cno

join student s on s.sno=sc.sno where sc.sno='0811101'

(2) 查询指定系在指定课程(课程号)的考试平均成绩。

create function dbo.Avg_Grade(@dept nvarchar(20), @cno char(6)) returns int as begin

declare @Avg int

select @Avg=avg(grade) from sc join student s on sc.sno=s.sno where dept=@dept and sc.cno=@cno return @Avg end

select distinct dbo.Avg_Grade(dept,cno) as 平均成绩 from sc join student s on sc.sno=s.sno

where dept='计算机系' and sc.cno='C001'

(3) 查询指定系的男生中选课门数超过指定门数的学生人数。

create function dbo.Man(@dept nvarchar(20),@menshu int) returns int as begin

declare @Num int

select @Num=count(*) from(select sc.sno,count(sc.cno) as b from student s left join sc on s.sno=sc.sno

where dept=@dept and sex='男' group by sc.sno

having count(sc.cno)>@menshu) as t return @Num end select distinct dbo.Man(dept,0) 学生人数 from student s left join sc on s.sno=sc.sno where dept='计算机系'

7.创建满足下述要求的用户自定义内联表值函数。

(1) 查询选课门数在指定范围内的学生的姓名、所在系和所选的课程。

create function dbo.F_7_1(@menshu int) returns table as

return(

select sname,dept,sc.cno,cname from Student s join SC on s.Sno=sc.Sno

join Course c on c.Cno = SC.Cno where s.sno in ( select sno from sc group by sno

having count(*)=@menshu)) select * from dbo.F_7_1(3)

(2) 查询指定系的学生考试成绩大于等于90的学生的姓名、所在系、课程名

和考试成绩。并写出利用此函数查询计算机系学生考试情况的SQL语句,只列出学生姓名、课程名和考试成绩。

create function dbo.F_7_2(@dept char(20)) returns table as

return(select sname,dept,cname,grade from Student s join SC on s.Sno=sc.Sno

join Course c on c.Cno = SC.Cno where dept=@dept and grade>=90)

select sname,cname,grade from dbo.F_7_2('计算机系')

8.创建满足下述要求的用户自定义多语句表值函数。

(1) 查询指定系年龄最大的前2名学生的姓名和年龄,包括并列的情况。

alter function dbo.F_8_1(@dept char(20)) returns @ret_F_8_1 table( sname char(10), age int) as begin

insert into @ret_F_8_1

select top 2 WITH TIES sname,year(GETDATE())-year(Birthday) age from student where dept=@dept order by age DESC return end

select sname,age from dbo.F_8_1('计算机系')

(2) 查询指定学生(姓名)的考试情况,列出姓名、所在系、修的课程名和

考试情况,其中考试情况列的取值为:如果成绩大于等于90,则为“优”;如果成绩在80~89,则为“良好”;如果成绩在70~79,则为“一般”;如果成绩在60~69,则为“不太好”;如果成绩小于60,则为“很糟糕”。并写出利用此函数查询李勇的考试情况的SQL语句。 alter function dbo.F_8_2(@sname char(10)) returns @ret_F_8_2 table( sname char(10), dept char(20), cname char(20),

GStye char(6)) as begin

insert into @ret_F_8_2

select sname,dept,cname,case when grade >=90 then '优'

when grade between 80 and 89 then'良好' when grade between 70 and 79 then'一般' when grade between 60 and 69 then'不太好' when grade <60 then'很糟糕'

end

from Student s join SC on s.Sno=sc.Sno join Course c on c.Cno = SC.Cno

where sname=@sname return end

select sname,dept,cname,gstye from dbo.F_8_2('刘晨')

select sname,dept,cname,gstye from dbo.F_8_2('李勇')

9.创建满足下述要求的游标。

(1)查询VB课程的考试情况,并按如下形式显示结果数据:

选了VB课程的学生情况:

姓名 所在系 成绩 李勇 计算机系 86 刘晨 计算机系 78 吴宾 信息系 75 张海 信息系 68 print '选了VB课程的学生情况:' print' '

print '姓名 所在系 成绩' declare @s char(10),@d char(20),@g int declare C_9_1 cursor for

select sname,dept,grade from Student s join SC on s.Sno=sc.Sno join Course c on c.Cno = SC.Cno where cname='VB' open C_9_1

fetch next from C_9_1 into @s,@d,@g while @@fetch_status=0 begin

print' '

print @s+@d+cast(@g as char(4)) fetch next from C_9_1 into @s,@d,@g end

close C_9_1

deallocate C_9_1

(2)统计每个系的男生人数和女生人数,并按如下形式显示结果数据。

系名 性别 人数 ====================

计算机系 男 2 计算机系 女 1 数学系 男 1 数学系 女 1 信息系 男 2 信息系 女 1

print '系名 性别 人数' print '===================='

declare @d char(10),@s char(2),@c int declare C_9_2 cursor for

select dept,sex,count(*) 人数 from Student group by dept,sex order by dept open C_9_2

fetch next from C_9_2 into @d,@s,@c while @@fetch_status=0 begin

print' '

print @d+' '+@s+' '+cast(@c as char(4)) fetch next from C_9_2 into @d,@s,@c end

close C_9_2

deallocate C_9_2

(3)列出每个系的学生信息,要求首先列出一个系的系名,然后在该系名下列出本系学生的姓名和性别;再列出下一个系名,然后在此系名下再列出该系的学生姓名和性别;以此类推,直至列出全部系。要求按如下形式显示结果数据:

计算机系学生:

李勇 计算机系 刘晨 计算机系 王敏 计算机系 ===================== 数学系学生:

钱小平 数学系 王大力 数学系 ===================== 信息系学生:

张立 信息系 吴宾 信息系 张海 信息系 =====================

declare @dept varchar(20),@sname char(10) declare C_9_3 cursor for

select distinct dept from student open C_9_3

fetch next from C_9_3 into @dept while @@fetch_status=0 begin

print @dept+':'

declare C_3 cursor for

select sname,dept from student where dept=@dept open C_3

fetch next from C_3 into @sname,@dept while @@fetch_status=0 begin

print @sname+@dept

fetch next from C_3 into @sname,@dept end

close C_3

deallocate C_3

print'======================' fetch next from C_9_3 into @dept end

close C_9_3

deallocate C_9_3

(4)设有工作表,结构如下:

Job(

Jobid char(4) primary key, --工作编号 desc varchar(40), --工作描述 lvl tinyint) --工作级别 设此表包含的数据如表7-2所示。

Jobid J01 J02 J03 J04 J05 表7-2 Job表的数据 desc 软件开发 10 硬件开发 12 软件测试 10 硬件维护 8 硬件测试 12 lvl 用游标实现对此表数据的如下修改:将工作级别相同的工作只保留工作编号

较小的一项工作,同时,将这些工作的工作描述拼接为一个工作描述,中间用逗号分隔。修改后的数据示意如下: Jobid J_desc lvl J01 软件开发,软件测试 10 J02 硬件开发,硬件测试 12 J04 硬件维护 8 create table #Job(Jobid char(4)primary key,[desc] varchar(40),lvl int) insert into #Job values('J01','软件开发',10) insert into #Job values('J02','硬件开发',12) insert into #Job values('J03','软件测试',10) insert into #Job values('J04','硬件维护',8) insert into #Job values('J05','硬件测试',12) create table #N_Job(Jobid char(4)primary key,[desc] varchar(40),lvl int) drop table #N_Job

declare @Jobid char(4),@desc varchar(40),@lvl int

declare C_9_4 cursor for select jobid,[desc],lvl from #job open C_9_4

fetch next from C_9_4 into @Jobid,@desc,@lvl while @@fetch_status=0 begin

if(exists(select * from #N_Job where lvl=@lvl)) begin

update #N_Job set [desc]=[desc]+','+@desc where lvl=@lvl end else begin

insert into #N_Job select @Jobid,@desc,@lvl end

fetch next from C_9_4 into @Jobid,@desc,@lvl end

close C_9_4

deallocate C_9_4

select * from #N_Job

三. 实验总结

因篇幅问题不能全部显示,请点此查看更多更全内容