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
 

 

 

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