一个学生表Students:
Id Name Sex
一个是学生得分表Scores(每天可以有多个得分记录):
Id Time Scoe
Time为得分的日期,Score为分数(非100制)。
create table Students ( Id int, Name nvarchar(20), Sex nchar(1) ) go create table Scores ( Id int, Time datetime, Score int ) go insert into Students select 1001,'小小','男' union all select 1002,'小强','男' go insert into Scores select 1001,'2012-1-1 10:00',1 union all select 1001,'2012-1-1 11:00',3 union all select 1001,'2012-1-1 13:00',4 union all select 1002,'2012-1-1 8:00',7 union all select 1002,'2012-1-1 8:00',8 union all select 1002,'2012-1-1 11:00',1 union all select 1001,'2012-1-8 8:00',4 union all select 1002,'2012-1-8 14:00',1 union all select 1002,'2012-1-8 15:00',5 union all select 1002,'2012-1-8 16:00',6 union all select 1001,'2012-1-15 8:00',5 union all select 1002,'2012-1-15 8:00',6 union all select 1001,'2012-1-21 8:00',7 union all select 1002,'2012-1-21 8:00',16 union all select 1001,'2012-1-29 8:00',15 union all select 1002,'2012-1-29 8:00',9 go
我希望得到的是一个月份统计表的结果,输入参数是一个月份,显示是这个月里面每天每位学生的得分情况,如果输入参数为2012-1-1:
Id Name Sex Time Score MaxScore MaxTime
1001 小小 男 2012-1-1 12 7 2012-1-1 9:00
1002 小强 男 2012-1-1 17 10 2012-1-1 9:30
1001 小小 男 2012-1-2 10 . .
1002 小强 男 2012-1-2 16 . .
.
.
.
.
1001 小小 男 2012-1-31 12 . .
1002 小强 男 2012-1-31 15 . .
MaxScore为当天最大得分,MaxTime为当天最大得分的时间。
下面是sql:
declare @startTime datetime ='2012-1-1 00:00:00'--输入参数,开始时间 declare @endTime datetime set @endTime = DATEADD(MM,1,@startTime)--结束时间 --创建一个保存数据的临时表 IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[#MyTable]') AND type in (N'U')) DROP TABLE [dbo].[#MyTable] create table #MyTable ( Id char(8), Name char(8), Sex char(8), Time datetime, Score decimal(8,3), MaxScoore decimal(8,3), MaxTime datetime ) --我先遍历时间,从开始到结束 while @startTime<@endTime begin insert into #MyTable (Id,Name,Sex,Time,Score,MaxScoore,MaxTime)--添加数据 select Students.Id, Students.Name,Students.Sex, @startTime as Time, (select sum(Score) from Scores where Time >= @startTime and Time< DATEADD(DD,1,@startTime) and Students.Id = Scores.Id ) as Score, (select MAX(Score) from Scores where Time >= @startTime and Time< DATEADD(DD,1,@startTime) and Students.Id = Scores.Id ) as MaxScore, --当天最大得分 (select top 1 Time from Scores where Time >= @startTime and Time< DATEADD(DD,1,@startTime) and Students.Id = Scores.Id order by Score desc ) as MaxTM --当天最大得分时间 from Students set @startTime = DATEADD(DD,1,@startTime) end
不知道可不可以优化,有其他方法也可以。
其中一个方案,别人提供的但是不太懂.
declare @date datetime set @date = '2012-01-01'; with ctea as --一个月的所有天,构成的列表 ( select dateadd(dd,number,@date) as time from master..spt_values where type = 'p' and dateadd(dd,number,@date) <= dateadd(dd,-day(dateadd(m,1,@date)),dateadd(m,1,@date)) ), cteb as ( select id, convert(varchar(10),[time],121) time, sum(Score) score, max([time]) maxtime, --最大时间,而我要的是最大得分时候的时间 max(Score) maxscore, cast(id as varchar)+convert(varchar(10),[time],121) un from Scores group by id,convert(varchar(10),[time],121) ), ctec as ( select id,name,sex, cast(id as varchar)+convert(varchar(10),time,121) un, convert(varchar(10),time,121) time from Students cross join ctea ) select c.id,c.name,c.sex,c.time,b.maxtime,b.score,b.maxscore from ctec c left join cteb b on c.un = b.un order by c.time
你后面实现的代码跟你描述的有点出入吧.看你的实现代码,应该是要变成这样:
select s.Id,s.Name,s.Sex,convert(date,s2.[Time]) as [time],sum(s2.Score) as Score,max(s2.Score) as MaxScore,max(s2.[Time]) as MaxTime from dbo.Students as s join dbo.Scores as s2 on s.Id = s2.Id group by s.Id,s.Name,s.Sex,convert(date,s2.[Time])
max(s2.[Time]) as MaxTime
虽然这个是最大时间,我要的是最值的发生时间。但我在套一个select,用select top 1 Time from scores where score = maxscore就获取了那个点的时间。没了循环性能的确提升了。
DECLARE @startTime DATETIME = '2012-1-1 00:00:00' --输入参数,开始时间 SELECT A.*, B.*, ( SELECT MAX (Score) FROM Scores WHERE DATEDIFF (dd, time, A.time)= 0 AND id= A.ID ) AS MaxScore, --当天最大得分 ( SELECT TOP 1 time from Scores WHERE DATEDIFF(dd, time, A.time) = 0 --按天比较 AND id = A.ID ORDER BY Score DESC ) AS MaxTM --当天最大得分时间 FROM Scores A LEFT JOIN Students B ON A.id = B.id WHERE DATEDIFF(mm, a.time, '2012-1-1') = 0 --按月比较
可以使用日期处理 结合子查询避免使用循环返回结果
select t2.Id,t2.Name,t2.Sex, t1.day from ( select Id,sum(Score) as Score,max(Score) as MaxScore,substr(Time,0,8) as day from Scores group by substr(Time,0,8),Id ) t1 left join Students t2 on t1.Id=t2.Id left join Scores t3 on t1.Id=t3.Id and t1.day=substr(t3.Time,0,8) and t1.MaxScore=t3.Score
把substr(Time,0,8)改成可运行的,忘了截取时间怎么写。。。
这个不行吗?