--開窗函數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