转自 毛琨同学
在TestDB数据库中, 编写一个存储过程proc_test_stat4,统计用户实验情况,要求:
1)无参数
2)在数据库中有表exercisebook, 用于保存用户的作业,包含下列字段
exerid 作业的唯一编号;
quesid 问题编号
userid 用户编号
eval 验证结果:start,success,error
posttime 提交时间
其中,数据的语义是
a)用户和问题是多对多关系,一个用户在答题过程中对同一个问题会产生多条记录;
b)验证结果中的start表示开始实验,success表示成功结束实验,error表示验证错误;
c)每个用户开始实验时会在exercisebook表中增加一条eval 内容是start的记录,其中包含开始时间;
d)开始实验后,每次提交都会在exercisebook表中增加一条记录,如果验证成功则eval 是success,若错误则eval 是error
e)如果在exercisebook表中没有关于userid和quesid的记录,则说明此用户还没有开始quesid的实验。
为更直观的观察用户的实验完成状态,请以用户为行,问题为列(仅考虑exercisebook中的所有userid和quesid)返回最近一次的提交情况,形如下表:(NULL表示实验未开始)
提示:这是经典的“行转列”问题。可以使用游标,也可以使用动态sql查询实现。
测试语句:
exec proc_test_stat4
create proc proc_test_stat4 as begin set nocount on; create table #temp( exerid bigint, userid bigint, quesid bigint, eval varchar(7), posttime datetime ) declare @exerid bigint,@userid bigint,@quesid bigint, @eval varchar(7),@posttime datetime declare cur cursor for select exerid,userid,quesid,eval,posttime from exercisebook open cur fetch next from cur into @exerid,@userid,@quesid,@eval,@posttime while @@fetch_status=0 begin if(not exists(select * from #temp where userid=@userid)) insert into #temp(exerid,userid,quesid,eval,posttime) values(@exerid,@userid,@quesid,@eval,@posttime) else update #temp set exerid=@exerid,quesid=@quesid,eval=@eval,posttime=@posttime where userid=@userid and posttime<@posttime fetch next from cur into @exerid,@userid,@quesid,@eval,@posttime end close cur deallocate cur --行转列-- declare @s nvarchar(4000) select @s=isnull(@s+',','')+quotename(quesid) from(select distinct quesid from #temp) as x declare @sq nvarchar(4000) set @sq='select b.* from #temp as a pivot(max(a.eval) for a.quesid in('+@s+')) as b' exec(@sq) set nocount off end