天天看點

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

繼續閱讀