SQL Server over()

--开窗函数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
 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章