一、分析函数
1、分析函数
分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计值。
2、分析函数和聚合函数的区别
普通的聚合函数用group by分组,每个分组返回一个统计值,而分析函数采用partition by分组,并且每组每行都可以返回一个统计值。
3、分析函数的形式
分析函数带有一个开窗函数over(),包含分析子句 。
分析子句又由下面三部分组成:
partition by :分组子句,表示分析函数的计算范围,不同的组互不相干;
ORDER BY: 排序子句,表示分组后,组内的排序方式;
ROWS/RANGE:窗口子句,是在分组(PARTITION BY)后,组内的子分组(也称窗口),此时分析函数的计算范围窗口,而不是PARTITON。窗口有两种,ROWS和RANGE;
使用形式如下:
OVER(PARTITION BY xxx PORDER BY yyy ROWS BETWEEN rowStart AND rowEnd)
注:窗口子句在这里我只说rows方式的窗口,range方式和滑动窗口也不提。
二、OVER() 函数
1、sql 查询语句的 order by 和 OVER() 函数中的 ORDER BY 的执行顺序
分析函数是在整个sql查询结束后(sql语句中的order by的执行比较特殊)再进行的操作, 也就是说sql语句中的order by也会影响分析函数的执行结果:
[1] 两者一致:如果sql语句中的order by满足分析函数分析时要求的排序,那么sql语句中的排序将先执行,分析函数在分析时就不必再排序;
[2] 两者不一致:如果sql语句中的order by不满足分析函数分析时要求的排序,那么sql语句中的排序将最后在分析函数分析结束后执行排序。
2、分析函数中的分组/排序/窗口
分析函数包含三个分析子句:分组(partition by), 排序(order by), 窗口(rows/range)
窗口就是分析函数分析时要处理的数据范围,就拿sum来说,它是sum窗口中的记录而不是整个分组中的记录,因此我们在想得到某个栏位的累计值时,我们需要把窗口指定到该分组中的第一行数据到当前行, 如果你指定该窗口从该分组中的第一行到最后一行,那么该组中的每一个sum值都会一样,即整个组的总和。
[A] range是逻辑窗口(值):是指定当前行对应值的范围取值,列数不固定,只要行值在范围内,对应列都包含在内。
如:SUM(id) OVER ( ORDER BY id RANGE BETWEEN 1 PRECEING AND 2 FOLLOWING ),分析:
当id=1时,是 1-1<=id<=1+2 的所有id值求和,即sum=1+1+3=5(取id为1,1,3);
当id=3时,是3-1<=id<=3+2 的所有id值求和,即sum=3(取id为3);
[B] rows是物理窗口(行):即根据order by 子句排序后,取的前N行及后N行的数据计算(与当前行的值无关,只与排序后的行号相关),
如:SUM(id) OVER ( ORDER BY id ROWS BETWEEN 1 PRECEING AND 2 FOLLOWING ),是取前1行到后2行的数据求和,分析:
当id=1时,前一行没数,,后二行是第3行,就是1到3行;
当id=3时,前一行是第2行,后二行是第5行,就是2到5行;
2.1 带有窗口子句
窗口子句,是在分组(PARTITION BY)后,组内的子分组(也称窗口),此时分析函数的计算范围窗口,而不是PARTITON。窗口有两种,ROWS和RANGE。若使用窗口子句,必须有ORDER BY 子句。
窗口子句中经常用到指定行:第一行(unbounded preceding),当前行(current row),最后一行(unbounded following),以及前num1行(num1 preceding )和 后num2行(num2 following)。
窗口子句不能单独出现,必须有order by子句时才能出现,如:
last_value(sal) over(partition by deptno order by sal rows between unbounded preceding and unbounded following)
以上示例指定窗口为整个分组。而出现order by子句的时候,不一定要有窗口子句,但效果会很不一样,此时的窗口默认是当前组的第一行到当前行!
2.2 当省略窗口子句时:
[1] 如果存在order by则默认的窗口是unbounded preceding and current row --当前组的第一行到当前行
[2] 如果同时省略order by则默认的窗口是unbounded preceding and unbounded following --整个组
2.3 如果省略分组,则把全部记录当成一个组:
[1] 如果存在order by则默认窗口是unbounded preceding and current row --当前组的第一行到当前行
[2]如果这时省略order by则窗口默认为unbounded preceding and unbounded following --整个组
三、常用分析函数
1、排名函数
函数为每条记录产生一个从1开始至n的自然数,n的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。
1.1 row_number() over()
row_number()返回一个唯一的值,当碰到相同数据时,排名按照记录集中记录的顺序依次递增。
1.2 rank() over()
rank()返回一个唯一的值,当碰到相同的数据时,此时所有相同数据的排名是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间空出排名。
1.3 dense_rank() over()
dense_rank()返回一个唯一的值,当碰到相同数据时,此时所有相同数据的排名都是一样的,同时会在最后一条相同记录和下一条不同记录的排名之间紧邻递增。
2、聚合函数
2.1 count() over()
2.2 max() over()
2.3 min() over()
2.4 sum() over()
2.5 avg() over()
3、 求最值对应的其他属性
3.1 first_value() over():第一个值
3.2 last_value() over():最后一个值
4、求之前或之后的第N行
注:行比较分析函数lead和lag无window(窗口)子句。
lag(arg1,arg2,arg3) 和 lead(arg1,arg2,arg3) 可以在一次查询中取出同一字段的前n行的数据和后n行的值。这种操作可以使用对相同表的表连接来实现,不过使用lag和lead有更高的效率。
[1] arg1:参数是列名,
[2] arg2:参数是偏移的offset,
[3] arg3:参数是超出记录窗口时的默认值。
4.1 lag() over()
lag()函数向下偏移。
4.2 lead() over()
lead()函数是向上偏移。
举例如下:
select * from kkk;
ID NAME
---------- --------------------
1 1name
2 2name
3 3name
4 4name
5 5name
select id,name,lag(name,1,0) over(order by id) from kkk;
ID NAME LAG(NAME,1,0)OVER(ORDERBYID)
---------- -------------------- ----------------------------
1 1name 0
2 2name 1name
3 3name 2name
4 4name 3name
5 5name 4name
select id,name,lead(name,1,0) over(order by id) from kkk;
ID NAME LEAD(NAME,1,0)OVER(ORDERBYID)
---------- -------------------- -----------------------------
1 1name 2name
2 2name 3name
3 3name 4name
4 4name 5name
5 5name 0
select id,name,lead(name,2,0) over(order by id) from kkk;
ID NAME LEAD(NAME,2,0)OVER(ORDERBYID)
---------- -------------------- -----------------------------
1 1name 3name
2 2name 4name
3 3name 5name
4 4name 0
5 5name 0
select id,name,lead(name,1,'linjiqin') over(order by id) from kkk;
ID NAME LEAD(NAME,1,'ALSDFJLASDJFSAF')
---------- -------------------- ------------------------------
1 1name 2name
2 2name 3name
3 3name 4name
4 4name 5name
5 5name linjiqin
---------------------------------------------------------------------------------------
5、排列组合函数,只能用在 GROUP BY 后边
5.1 group by rollup(a, b, c):
首先会对(a、b、c)进行group by,
然后再对(a、b)进行group by,
其后再对(a)进行group by,
最后对全表进行汇总操作。
5.2 group by cube(a, b, c):
首先会对(a、b、c)进行group by,
然后依次是(a、b),(a、c),(a),(b、c),(b),(c),
最后对全表进行汇总操作。
5.3 示例如下:
5.3.1 普通 group by 分组
sql> select owner, index_type, status, count(*) from t where owner like 'SY%' group by owner, index_type, status;
5.3.2 GROUP BY ROLLUP(A, B, C):
首先会对(A、B、C)进行GROUP BY,
然后再对(A、B)进行GROUP BY,
其后再对(A)进行GROUP BY,
最后对全表进行汇总操作。
select owner, index_type, status, count(*) from t where owner like 'SY%' group by ROLLUP(owner, index_type, status);
5.3.3 GROUP BY CUBE(A, B, C):
首先会对(A、B、C)进行GROUP BY,
然后依次是(A、B),(A、C),(A),(B、C),(B),(C),
最后对全表进行汇总操作。
select owner, index_type, status, count(*) from t where owner like 'SY%' group by cube(owner, index_type, status);