--开窗函数over()不需要使用group by 就可以对数据进行分组。还可以同时返回基础行的所有列和聚合列。
--over 函数 配合聚合函数(max、min、sum、avg、count等)或row_number等函数,可以在不改变原显示数据的情况下,
--新增一列作为聚合函数的计算值;
--group by 子句只能同聚合函数(max、min、sum、avg、count),对相关列进行分组,只能展示出分组列和聚合列的数据。
--1、partition by 用于将结果集进行分组,开窗函数应用于每一组。
--2、order by 用于排序。
--3、row_number()为每一组的行按顺序生成一个惟一的序号
--4、rank()也为每一组的行生成一个序号,但不同于row_number(),如果按照order by 排序,如果有相同的值会生成相同的序号。
--并且接下来生成的序号是不连续的。
--5、dense_rank()与rank()相似。不同的是,如果有相同的序号,那接下来的序号不会间断。也就是接下来的序号是连续的。
--6、NTILE:按指定数目将数据进行分组。并为每组生成一个序号。
--7、窗口框架范围限定方式:一种是使用ROWS子句,通过指定当前行之前或之后的固定数目的行来限制分区中的行数;
--另一种是RANGE子句,按照排序列的当前值,根据相同值来确定分区中的行数。
--注意:聚合函数不能与ORDER BY 一同使用。
实例如下:
create table Student(
Sid int primary key identity(1,1) not null,
StudentName varchar(50) not null,
Age int null,
Sex varchar(2) check(sex='male' or sex='remale'),
Birthday datetime
)create table ProjectTb(
Pid int primary key identity(1,1) not null,
ProjectName varchar(20) not null,
orderNum int
)create table Score(
ScoreID int primary key identity(1,1) not null,
Sid int foreign key references Student(Sid) not null,
Pid int foreign key references ProjectTb(Pid) not null,
Score int
)
--insert into dbo.Student(StudentName,Age,Sex,Birthday)
--values('Lucy',21,'remale','1990-09-09'),('Lilei',22,'male','1989-01-03'),('Hanmeimei',20,'remale','1991-03-05')--insert into dbo.ProjectTb(ProjectName,orderNum) values('Math',1),('English',2),('Chinese',3)
--insert into dbo.Score(Sid,Pid,Score)
--values(1,1,90),(1,2,67),(1,3,84),(2,1,90),(2,2,62),(2,3,87),(3,1,80),(3,2,83),(3,3,89)
--1、求学生的平均成绩:
--(1)使用group by
select s.StudentName,avg(sco.Score) as avg_score
from dbo.Score sco left join dbo.Student s
on sco.Sid=s.Sid
group by sco.Sid,s.StudentName
--(2)使用over()
with ScoreInfo as(
select *,avg(Score) over(partition by Sid) avg_score from dbo.Score
)
select distinct(sco.avg_score),s.StudentName
from ScoreInfo sco left join dbo.Student s
on sco.Sid=s.Sid
--此情形下,比较使用group by、over()。使用group by的话,想要select的列都必须受限于group by 。
--但over()就不一样了。聚合列之外的所有数据行的列都可随意select。
--2、求每个科目的平均成绩(与1同理)
--(1)使用group by
select p.ProjectName,avg(s.Score) as avg_score
from dbo.Score s left join dbo.ProjectTb p
on s.Pid=p.Pid
group by s.Pid,p.ProjectName
--(2)使用over()
with ScoreInfo as(
select *,avg(Score) over(partition by Pid) avg_score from dbo.Score
)
select distinct(sco.avg_score),p.ProjectName
from ScoreInfo sco left join dbo.ProjectTb p
on sco.Pid=p.Pid--3、求每个学生的最好成绩的科目
with ScoreInfo as (
select max(Score) over(partition by Sid) as max_score,ScoreID,Sid,Pid,Score
from dbo.Score
)
select s.StudentName,p.ProjectName,sco.Score
from ScoreInfo sco
left join dbo.Student s
on sco.Sid=s.Sid
left join dbo.ProjectTb p
on sco.Pid=p.Pid
where sco.Score=sco.max_score
order by sco.Score desc--4、求每个科目最好成绩(包含对应的学生)(同理于3)
with ScoreInfo as(
select max(Score) over(partition by Pid) as max_score,*
from dbo.Score
)
select p.ProjectName,s.StudentName,sco.Score
from ScoreInfo sco
left join dbo.Student s
on sco.Sid=s.Sid
left join dbo.ProjectTb p
on sco.Pid=p.Pid
where sco.Score=sco.max_score
order by sco.Score desc--5、获取每个学生按成绩高到低排序,并显示相关科目。
with ScoreInfo as(
select *,row_number() over(partition by Sid order by Score desc) number from dbo.Score
)
select s.StudentName,p.ProjectName,sco.Score,sco.number
from ScoreInfo sco left join dbo.Student s
on sco.Sid=s.Sid
left join dbo.ProjectTb p
on sco.Pid=p.Pid--6、获取每个科目成绩由高到低排序,并显示相应的学生(同理于5)
with ScoreInfo as(
select *,row_number() over(partition by Pid order by Score desc) number from dbo.Score
)
select p.ProjectName,s.StudentName,sco.Score,sco.number
from ScoreInfo sco left join dbo.ProjectTb p
on sco.Pid=p.Pid
left join dbo.Student s
on sco.Sid=s.Sid
--7、对6进行改进,并分数相同的显示为并列
with ScoreInfo as(
select *,rank() over(partition by Pid order by Score desc) number from dbo.Score
)
select p.ProjectName,s.StudentName,sco.Score,sco.number
from ScoreInfo sco left join dbo.ProjectTb p
on sco.Pid=p.Pid
left join dbo.Student s
on sco.Sid=s.Sid
--8、对7再进行改进,并分数相同的显示为并列,把自然顺序的第3显示为第2。
--相当于Math这一科目,有2个第1名,1个第2名。不能没有第2名,直接跳到第3名了,是吧
with ScoreInfo as(
select *,dense_rank() over(partition by Pid order by Score desc) number from dbo.Score
)
select p.ProjectName,s.StudentName,sco.Score,sco.number
from ScoreInfo sco left join dbo.ProjectTb p
on sco.Pid=p.Pid
left join dbo.Student s
on sco.Sid=s.Sid--9、NTILE()按指定数目进行分组。这个感觉比较随机,想到是小朋友做游戏的分组了,哈。。。
--成绩表分组。正好我们的成绩表有9条数据,分3组。
with ScoreInfo as(
select *,NTILE(3) over(order by Sid) rn from dbo.Score
)
select * from ScoreInfo--10、在9的基础上,再玩一下,是不是可以计算出这3组成员的总成绩呢?
with ScoreInfo as(
select *,NTILE(3) over(order by Sid) rn from dbo.Score
)
select sum(Score) from ScoreInfo
group by rn--11、求每个学生的总成绩
with ScoreInfo as(
select *,sum(Score) over(partition by Sid) score_sum
from dbo.Score
)
select distinct(sco.score_sum),s.StudentName
from ScoreInfo sco left join dbo.Student s
on sco.Sid=s.Sid--总提示“'ROWS' 附近有语法错误。”。
select *,
sum(Score) over(ORDER BY Pid ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as row1,
--sum(Score) over(partition by Sid order by Pid) row1,
--sum(Score) over(partition by Sid order by Pid rows between unbounded preceding and current row) row2
from dbo.Score
--12、求各科目的总成绩
with ScoreInfo as(
select *,sum(Score) over(partition by Pid) score_sum
from dbo.Score
)
select distinct(sco.score_sum),p.ProjectName
from ScoreInfo sco left join dbo.ProjectTb p
on sco.Pid=p.Pid