oracle分析函数技术详解(配上开窗函数over())
一、Oracle分析函数入门分析函数是什么? 分析函数和聚合函数的不同之处是什么? 分析函数的形式 分析函数例子(在scott用户下模拟) 示例目的:显示各部门员工的工资,并附带显示该部分的最高工资。 --显示各部门员工的工资,并附带显示该部分的最高工资。 SELECT E.DEPTNO,E.EMPNO,E.ENAME,E.SAL,LAST_VALUE(E.SAL) OVER(PARTITION BY E.DEPTNO ORDER BY E.SAL ROWS --unbounded preceding and unbouned following针对当前所有记录的前一条、后一条记录,也就是表中的所有记录 --unbounded:不受控制的,无限的 --preceding:在...之前 --following:在...之后 BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) MAX_SAL FROM EMP E; 运行结果:
示例目的:按照deptno分组,然后计算每组值的总和 SELECT EMPNO,ENAME,DEPTNO,SAL,SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY ENAME) max_sal FROM SCOTT.EMP; 运行结果: 示例目的:对各部门进行分组,并附带显示第一行至当前行的汇总 SELECT EMPNO,--注意ROWS BETWEEN unbounded preceding AND current row 是指第一行至当前行的汇总 SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_sal FROM SCOTT.EMP; 运行结果: 示例目标:当前行至最后一行的汇总 SELECT EMPNO,--注意ROWS BETWEEN current row AND unbounded following 指当前行到最后一行的汇总 SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) max_sal FROM SCOTT.EMP; 运行结果: 示例目标:当前行的上一行(rownum-1)到当前行的汇总 SELECT EMPNO,--注意ROWS BETWEEN 1 preceding AND current row 是指当前行的上一行(rownum-1)到当前行的汇总 SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) max_sal FROM SCOTT.EMP; 运行结果: 示例目标:当前行的上一行(rownum-1)到当前行的下辆行(rownum+2)的汇总 SELECT EMPNO,--注意ROWS BETWEEN 1 preceding AND 1 following 是指当前行的上一行(rownum-1)到当前行的下辆行(rownum+2)的汇总 SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING) max_sal FROM SCOTT.EMP; 运行结果: 二、理解over()函数1.1、两个order by的执行时机 a) 两者一致:如果sql语句中的order by满足与分析函数配合的开窗函数over()分析时要求的排序,即sql语句中的order by子句里的内容和开窗函数over()中的order by子句里的内容一样, 那么sql语句中的排序将先执行,分析函数在分析时就不必再排序; 那么sql语句中的排序将最后在分析函数分析结束后执行排序。
1.2、开窗函数over() 窗口子句在这里我只说rows方式的窗口,range方式和滑动窗口也不提。 窗口子句中我们经常用到指定第一行,当前行,最后一行这样的三个属性: 注释: 当开窗函数over()出现分组(partition by)子句时, unbounded preceding即第一行是指表中一个分组里的第一行, unbounded following即最后一行是指表中一个分组里的最后一行; 当开窗函数over()省略了分组(partition by)子句时, unbounded preceding即第一行是指表中的第一行, unbounded following即最后一行是指表中的最后一行。
例如: last_value(sal) over(partition by deptno
order by sal
rows between unbounded preceding and unbounded following)
以上示例指定窗口为整个分组。而出现order by子句的时候,不一定要有窗口子句,但效果会很不一样,此时的窗口默认是当前组的第一行到当前行! 如果省略分组,则把全部记录当成一个组。 而无论是否省略分组子句,如下结论都是成立的: 1、窗口子句不能单独出现,必须有order by子句时才能出现。 2、当省略窗口子句时:
lag(sal) over(order by sal) 解释 over(order by salary)表示意义如下: 首先,我们要知道由于省略分组子句,所以当前组的范围为整个表的数据行, 然后,在当前组(此时为整个表的数据行)这个范围里执行排序(即order by salary), 最后,我们知道分析函数lag(sal)在当前组(此时为整个表的数据行)这个范围里的窗口范围为当前组的第一行到当前行,即分析函数lag(sal)在这个窗口范围执行。 参见:
Oracle的LAG和LEAD分析函数
Oracle分析函数ROW_NUMBER()|RANK()|LAG()使用详解1.3、帮助理解over()的实例 例1:关注点:sql无排序,over()排序子句省略 SELECT DEPTNO,EMPNO,LAST_VALUE(SAL) OVER(PARTITION BY DEPTNO) FROM EMP; 运行结果: SELECT DEPTNO,LAST_VALUE(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) FROM EMP; 运行结果: SELECT DEPTNO,LAST_VALUE(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) MAX_SAL FROM EMP; 运行结果: SELECT DEPTNO,MGR,HIREDATE,LAST_VALUE(SAL) OVER(PARTITION BY DEPTNO) LAST_VALUE FROM EMP WHERE DEPTNO = 30 ORDER BY DEPTNO,MGR; 运行结果:
SELECT DEPTNO,MGR DESC; 运行结果: SELECT DEPTNO,MIN(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL ASC) LAST_VALUE FROM EMP WHERE DEPTNO = 30 ORDER BY DEPTNO,MGR DESC; 运行结果: SELECT DEPTNO,MIN(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) LAST_VALUE FROM EMP WHERE DEPTNO = 30 ORDER BY DEPTNO,MGR DESC; 运行结果: 三、常见分析函数详解为了方便进行实践,特将演示表和数据罗列如下: 一、创建表 create table t( bill_month varchar2(12),area_code number,net_type varchar(2),local_fare number ); 二、插入数据 insert into t values('200405',5761,'G',7393344.04); insert into t values('200405','J',5667089.85); insert into t values('200405',5762,6315075.96); insert into t values('200405',6328716.15); insert into t values('200405',5763,8861742.59); insert into t values('200405',7788036.32); insert into t values('200405',5764,6028670.45); insert into t values('200405',6459121.49); insert into t values('200405',5765,13156065.77); insert into t values('200405',11901671.70); insert into t values('200406',7614587.96); insert into t values('200406',5704343.05); insert into t values('200406',6556992.60); insert into t values('200406',6238068.05); insert into t values('200406',9130055.46); insert into t values('200406',7990460.25); insert into t values('200406',6387706.01); insert into t values('200406',6907481.66); insert into t values('200406',13562968.81); insert into t values('200406',12495492.50); insert into t values('200407',7987050.65); insert into t values('200407',5723215.28); insert into t values('200407',6833096.68); insert into t values('200407',6391201.44); insert into t values('200407',9410815.91); insert into t values('200407',8076677.41); insert into t values('200407',6456433.23); insert into t values('200407',6987660.53); insert into t values('200407',14000101.20); insert into t values('200407',12301780.20); insert into t values('200408',8085170.84); insert into t values('200408',6050611.37); insert into t values('200408',6854584.22); insert into t values('200408',6521884.50); insert into t values('200408',9468707.65); insert into t values('200408',8460049.43); insert into t values('200408',6587559.23); insert into t values('200408',7342135.86); insert into t values('200408',14450586.63); insert into t values('200408',12680052.38); commit;
三、first_value()与last_value():求最值对应的其他属性 SELECT BILL_MONTH,AREA_CODE,SUM(LOCAL_FARE) LOCAL_FARE,FIRST_VALUE(AREA_CODE) OVER(PARTITION BY BILL_MONTH ORDER BY SUM(LOCAL_FARE) DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) FIRSTVAL,LAST_VALUE(AREA_CODE) OVER(PARTITION BY BILL_MONTH ORDER BY SUM(LOCAL_FARE) DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) LASTVAL FROM T GROUP BY BILL_MONTH,AREA_CODE ORDER BY BILL_MONTH 运行结果: 四、rank(),dense_rank()与row_number():求排序 rank,dense_rank,row_number函数为每条记录产生一个从1开始至n的自然数,n的值可能小于等于记录的总数。这3个函数的唯一区别在于当碰到相同数据时的排名策略。 演示数据在Oracle自带的scott用户下: SELECT * FROM (SELECT DEPTNO,RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RW,SAL FROM SCOTT.EMP) WHERE RW <= 4; 运行结果:
SELECT * FROM (SELECT DEPTNO,DENSE_RANK() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RW,SAL FROM SCOTT.EMP) WHERE RW <= 4; 运行结果:
SELECT * FROM (SELECT DEPTNO,ROW_NUMBER() OVER(PARTITION BY DEPTNO ORDER BY SAL DESC) RW,SAL FROM SCOTT.EMP) WHERE RW <= 4; 运行结果: 五、lag()与lead():求之前或之后的第N行 SQL> select id,lead(name,0) over(order by id) from kkk; SQL> select id,2,0) over(order by id) from kkk; --------------------------------------------------------------------------------------- 六、rollup()与cube():排列组合分组
2)、group by cube(a,c): 1、生成演示数据: 2、普通group by体验 3、group by rollup(A,B,C) 4、group by cube(A,C) sql> select owner,count(*) from t where owner like 'SY%' group by cube(owner,status);
七、max(),min(),sun()与avg():求移动的最值总和与平均值 SELECT AREA_CODE,BILL_MONTH,LOCAL_FARE,SUM(LOCAL_FARE) OVER(PARTITION BY AREA_CODE ORDER BY TO_NUMBER(BILL_MONTH) RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) "3month_sum",AVG(LOCAL_FARE) OVER(PARTITION BY AREA_CODE ORDER BY TO_NUMBER(BILL_MONTH) RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) "3month_avg",MAX(LOCAL_FARE) OVER(PARTITION BY AREA_CODE ORDER BY TO_NUMBER(BILL_MONTH) RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) "3month_max",MIN(LOCAL_FARE) OVER(PARTITION BY AREA_CODE ORDER BY TO_NUMBER(BILL_MONTH) RANGE BETWEEN 1 PRECEDING AND 1 FOLLOWING) "3month_min" FROM (SELECT T.AREA_CODE,T.BILL_MONTH,SUM(T.LOCAL_FARE) LOCAL_FARE FROM T GROUP BY T.AREA_CODE,T.BILL_MONTH) 运行结果: 问题:求各地区按月份累加的通话费 SELECT AREA_CODE,SUM(LOCAL_FARE) OVER(PARTITION BY AREA_CODE ORDER BY BILL_MONTH ASC) "last_sum_value" FROM (SELECT T.AREA_CODE,T.BILL_MONTH) ORDER BY AREA_CODE,BILL_MONTH 运行结果: -------------------------------------------------------------------------- 另见:《Oracle分析函数ROW_NUMBER()|RANK()|LAG()使用详解》 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |