欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享,与更多的人进行学习交流
本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习,有基础也有进阶,有MySQL也有Oracle
:传送门分析函数
:传送门统计分析函数
:传送门排序分析函数
row 物理行 与行中的值是没有关系的
range 逻辑行 与行中的值是有关系的
select e.*,
first_value(empno) over (partition by deptno order by sal) rn
from emp e;
select e.*,
first_value(empno) over (partition by deptno order by sal
range between unbounded preceding and current row -- 忽略的Windows子句,与上面没有加Windows子句的sql命令的作用是一样的
) rn
from emp e;
range between unbounded preceding and current row
指定了要统计的窗口范围,这个窗口范围也是面向行的,只是比partiton
更细,先partiton
分组,再按组里面看窗口范围range
的窗口范围是负无穷 ~ 当前值(range逻辑行,当前行与行中的值有关,所以到当前值)
,负无穷是每个组的最上面,正无穷在每个组的下面rows
看的是物理行,与行中的值是没有关系的select e.*,
first_value(empno) over (partition by deptno order by sal
rows between unbounded preceding and current row
) rn
from emp e;
first_value
换成 last_value
,观察 range
和 rows
select e.*,
last_value(empno) over (partition by deptno order by sal
range between unbounded preceding and current row) rn
from emp e;
select e.*,
last_value(empno) over (partition by deptno order by sal
rows between unbounded preceding and current row) rn
from emp e;
rows between ... preceding and ...
select e.*,
last_value(empno) over (partition deptno order by sal
rows between 1 preceding and 1 following) rn
from emp e;
range between ... preceding and ...
range
是逻辑行,与值有关,所以在...
中填写的内容应该根据表格中的值来决定select e.*,
last_value(empno) over (partition by deptno order by sal
range between 400 preceding and 400 following) rn
from emp e;
select t.*,sum(sal) over(partition by deptno order by sal) cum_sum from emp t; -- 分析函数可以写group by,但是不需要
在order by
后面默认忽略了一个子句range between unbounded preceding and current row
,即默认忽略了一个逻辑行的(-∞~当前值)的子句
使用rows
进行改进,以达到想要的累计效果
select t.*,
sum(sal) over(partition by deptno order by sal
rows between unbounded preceding and current row
) cum_sum
from emp t;
select t.*,
sum(sal) over(partition by deptno order by sal
rows between unbounded preceding and current row
) cum_sum
from emp t;
select t.*,
sum(sal) over(partition by deptno order by sal,rowid) cum_sum -- 使用rowid,相当于实现了一个物理行的统计
from emp t;
# oracle 也可以使用rowid,因为rowid是指向内存的唯一的地址,是决定数据库如果找到记录的,这个行号是唯一的
select t.*,
count(sal) over(partition by deptno order by sal,rowid) cum_sum
from emp t;
# 效果与row_number() over()有点像
select t.*,
max(sal) over(partition by deptno order by sal) cum_sum -- 求得是最大值,所以就不能用物理行了
from emp t;
# 按照部门编号进行分区,然后使用sum()得到每个组的薪水和
select t.*,
sum(sal) over(partition by deptno) cum_sum
from emp t;
# 统计每组有薪水的人数,因为count()动态忽略null
select t.*,
count(sal) over(partition by deptno) cum_sum
from emp t;
# 求出了所有人的薪水和
# 分析函数不会减少行数,数据有几行,求完和的结果就有几行
select t.*,
sum(sal) over cum_sum
from emp t;
select sal,sal/sum(sal) over() cum_sum,sal/(select sum(sal) from emp) from emp;