over在聚合函数中的使用:
一般格式:
聚合函数名(列) over(选项)
over必须与聚合函数或排序函数一起使用,聚合函数为:
sum(),max(),min(),count(),avg()
排序函数为:
rank(),row_number(),dense_rank(),ntile()
over表示把函数当成开窗函数而不是聚合函数,SQL标准允许将所有聚合函数用做开窗函数,使用over关键字来区分这两种用法。
开窗函数不需要使用group by就可以对数据进行分组,就可以同时返回基础行的列和聚合列。
开窗函数sum(*) over(),对于查询结果的每一行都返回所有符合条件的行的条数,over关键字后的括号中还经常添加选项来改变进行聚合运算的窗口范围,如果over关键字后的括号中选项为空,则开窗函数会对结果集中的所有行进行聚合运算。
常用格式:
sum(*) over(partition by A order by B)
partition by:进行分组,得到对应组内的所有求和值
order by:按照B进行排序,得到对应组内的累计求和值(如果B为id,两个id相同,则这两个id返回的sum那一列是相同的聚合值,是累计到最后一个id对应值的和--下面的例子会详细说明)
order by 字段名 rows|range between 边界规则1 and 边界规则2
rows:表示按照行的范围进行范围的定位
range:表示按照取值的范围进行范围的定位
这两种不同的定位方式主要用来处理并列排序的情况(见下面的例子)
边界规则的可取值为:
current row--当前行
n preceding--前n行
unbounded preceding--一直到第一条记录
n following--后n行
unbounded following--一直到最后一条记录
'range/rows between 边界规则1 and 边界规则2':用来定位聚合计算范围,被称为定位框架。
eg:
1、建表
CREATE TABLE over2 (
FName VARCHAR(20),FCity VARCHAR(20),FAge INT,FSalary INT);
2、插入数据
INSERT INTO over2(FName,FCity,FAge,FSalary) VALUES
('Tom','BeiJing',20,3000),('Tim','ChengDu',21,4000),('Jim','BeiJing',22,3500),('Lily','London',21,2000),('John','NewYork',22,1000),('YaoMing','BeiJing',20,3000),('Swing','London',22,2000),('Guo','NewYork',20,2800),('YuQian','BeiJing',24,8000),('Ketty','London',25,8500),('Kitty','ChengDu',25,3000),('Merry','BeiJing',23,3500),
('Smith','ChengDu',30,3000),('Bill','BeiJing',25,2000),('Jerry','NewYork',24,3300);
3、关于partition by
(1)所属城市的人员数-按城市进行分组聚合
SELECT
*,
count( * ) over ( PARTITION BY Fcity )
FROM
over2;
(2)显示每一个人员的信息、所属城市的人员数以及同龄人的人数
SELECT
*,
count( * ) over ( PARTITION BY Fcity ) '所属城市人员数',
count( * ) over ( PARTITION BY FAge ) '所属同龄人员数'
FROM
over2;
在同一个SELECT语句中可以同时使用多个开窗函数,而且这些开窗函数并不会相互干扰。
4、关于order by的详解:
(1)查询从第一行到当前行的的工资总和
select FName,Fcity,FAge,FSalary,
sum(FSalary) over(order by FSalary rows between unbounded preceding and current row) '到当前行工资求和'
from over2;
(2)将上面的row换成range
select FName,Fcity,FAge,FSalary,
sum(FSalary) over(order by FSalary range between unbounded preceding and current row) '到当前行工资求和'
from over2;
结果和(1)的区别体现在红框和黄框部分,按照FSalary进行排序,row-按照行的范围进行范围定位,所以每一行后面对应的‘到当前行工资求和’都不一样,都严格的是第一行到当前行的累计和;range-按照取值的范围进行范围定位,虽然定位框架的语法仍然是从第一行到当前行的累计和,但是由于取值的范围:等于2000元的工资有3人,所以计算的累计为从第一条到2000元工资的最后一个人,写在每个2000元工资的人的后面都是7000。
(3)将(2)中的定位框架省略
range between unbounded preceding and current row
上述框架是开窗函数中最常用的定位框架,如果是这种框架的话,可以省略上述定位框架部分
SELECT
FName,
Fcity,
FAge,
FSalary,
sum( FSalary ) over ( ORDER BY FSalary ) '到当前行工资求和'
FROM
over2;
得到的结果和(2)的结果一样。
(4)将上面的sum()换成count(),计算工资排名
按照salary进行排序,然后计算从第一行(unbounded preceding)到当前行(current row)的人员的个数,相当于计算人员的的工资水平排名。
Question:
怎么让工资为2000元的排名都为2?--见后面排序函数的rank()和dence_rank()
5、关于over(partition by A order by B)
select FName,Fcity,FAge,FSalary,
sum(FSalary) over(partition by FAge order by FSalary) '同龄人的累计工资'
from over2;
over在排序函数中的使用:
一般格式:
排序函数(列) over(选项)
排序函数为:
rank(),dense_rank(),row_number(),ntile(),lead(),lag()
1、rank(),dense_rank(),row_number()的区别
select FName,Fcity,FAge,FSalary,
rank() over(order by FSalary desc) f_rank,
dense_rank() over(order by FSalary desc) f_dense_rank,
row_number() over(order by FSalary desc) f_row_number
from over2;
rank()与dense_rank()的区别:
两者都是计算一组数值中的排序值,
但是在有并列关系时,dence_rank中相关等级不会跳过,rank则跳过。
rank() 是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内)
dense_rank()是连续排序,有两个第二名时仍然跟着第三名。
row_number():
row_number over(partition by A order by B)
根据A分组,在分组内根据B排序,且得出来的值是每组内部排序后的顺序编号(组内连续的唯一的)
其主要是‘行’的信息,并没有排名。row_number()必须与order by一起使用,
多用于分页查询,比如查询10-100个学生。
select * from
(select *,row_number() over(order by FSalary DESC) paixu from over2) r
where r.paixu between 6 and 10;
2、ntile(x)--平均分区函数
select FName,Fcity,FAge,FSalary,
ntile(3) over(order by FSalary) 分区 from over2;
3、lag() over(partition by A order by B)
lead() over(partition by A order by B)
lag和lead中有三个参数,lag('列名',offset,'超出记录窗口时的默认值')
lag和lead可以获取,按一定顺序B排列的当前行的上下相邻若干offset的莫隔行的某个列。
lag()是向前,lead()是向后。
select FName,Fcity,FAge,FSalary,
lag(FSalary,1,'超出') over(order by FSalary DESC) f_lag向前,
lead(FSalary,1,'超出') over(order by FSalary DESC) f_lead向后
from over2;