小学生之Oracle分析函数
分析函数是什么?
分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计值。
分析函数和聚合函数的不同之处是什么?
普通的聚合函数用group by分组,每个分组返回一个统计值,而分析函数采用partition by分组,并且每组每行都可以返回一个统计值。
分析函数的形式
分析函数带有一个开窗函数over(),包含三个分析子句:分组(partition by), 排序(order by), 窗口(rows) ,他们的使用形式如下:over(partition by xxx order by yyy rows between zzz)。
注:窗口子句在这里我只说rows方式的窗口,range方式和滑动窗口也不提
分析函数例子(在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,
ENAME,
DEPTNO,
SAL,
--注意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,
ENAME,
DEPTNO,
SAL,
--注意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,
ENAME,
DEPTNO,
SAL,
--注意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,
ENAME,
DEPTNO,
SAL,
--注意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;
运行结果:

评级函数
常见评级函数如下:
- RANK():返回数据项在分组中的排名,在排名相等时会在名次中留下空位,造成排名不连续。
- DENSE_RANK():同样返回数据项在分组中排名,不过在排名相等时不会留下名位空位。
- CUME_DIST():返回特定值相对于一组值的位置,是累积分布(cumulative distribution)的简写。
- PERCENT_RANK():返回某个值相对于一组值的百分比排名。
- NTILE():返回n分片后的值,如三分片、四分片等。
- ROW_NUMBER():为每一条分组记录返回一个数字,注意不同于rownum伪列。
RANK()和DENSE_RANK()
rank()和dense_rank()函数都可用于计算数据项在分组中(在不使用partition by时以所有数据为一个分组)的排名。它们的区别在于rank()在排名相等时,如:有3个第1名时,则下一个排名为第4名,没有2、3名;而dense_rank()则在有3个第1名时,下一个排名为第2名。即,rank()会出现排名间隔,而dense_rank()则不会出现排名间隔。
这两个函数多用于select子句中,在不进行分组的情况下,可以不使用partition by子句。其使用举例如,找出公司所有人工资排名:
select ename,
rank() over (order by sal desc) rank,
dense_rank() over (order by sal desc) dense_rank
from emp;
从语句中可以看出,rank()函数需要有关键字over和order by。而且rank()是一个单值函数,而不是聚合函数。若需要找出每种工作的最高工资在所有工作最高工资中的排名:
select job,
rank() over (order by max(sal) desc) rank,
dense_rank() over (order by max(sal) desc) dense_rank
from emp
group by job;
在排名中,会出现NULL值在前在后的问题,可以在ORDER BY子句之后使用关键字NULLS FIRST/LAST来控制。
PARTITION BY子句
当需要进行获得分组后各组内的排名,则需要使用partition by子句。它不同于group by的分组,这种分组不“合并聚合”,它相当于把值分组后计算,然后重复每个值。
最常见的例子如:在table表中有name(姓名)、class(班级)和score(分数)三个字段,求每个班级里前三名姓名、班级及分数,SQL语句为:
select name,class,score
from (select name,
class,
score,
rank() over(partition by class order by score desc) rank
from table)
where rank <= 3;
在SCOTT用户中测试,求每个部门工资前3名的人姓名、部门、工作和工资,如:
select *
from (select ename,
deptno,
job,
sal,
dense_rank() over(partition by deptno order by sal desc) rank
from emp)
where rank <= 3;
ROW_NUMBER()
row_number为每一行返回一个数字,在分组中较常用(rownum在非分组中常用)。如,给emp表中每种工作工资由高到低进行排序:
select ename,job,sal,row_number() over (partition by job order by sal desc) from emp;
窗口函数(累计和、移动平均值等)
窗口函数可用来计算累计和、移动平均值和中心平均值等,具体如下:
计算累计和
查询从2003年1月到12月的累计销量,SQL语句如下:
SELECT month,
SUM(amount) AS month_amount,
SUM(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_amount
FROM all_sales
where year = 2003
GROUP BY month
ORDER BY month;
对于累计部分SUM(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)解析如下:
- SUM(SUM(amount))中内部的SUM(amount)用于计算月销量总和,外部的SUM()用于计算累计销量。
- ORDER BY month 按月份对查询读取的记录进行排序。
- ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW定义了窗口的起点和终点,起点为UNBOUNDED PRECEDING,意味着起点为固定的查询结果集的第一行;终点为CURRENT ROW表示终点为处理结果集的当前行。当外部SUM函数计算返回当前的累计销量后,窗口的终点便向下移动一行。PRECEDING表示向上累计数,若将UNBOUNDED换成数字如1,则表示跟之前一条记录做累积;同时还可以向后,使用关键字FOLLOWING,指定向后累积数只需要在该关键字前加数字即可,该数字为向后累积的行数(从这里也可以看出排序的重要性)。
如:
若要计算指定月份如6月到12月的累积销量,则只需要在where子句中再增加条件month between 6 and 12即可。
计算当月跟前3个月累积销量,窗口语句:
SUM(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS cumulative_amount
计算前一个月和后一个月累积销量,窗口语句:
SUM(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS cumulative_amount
计算移动平均值
计算本月与前3个月之间销量的移动平均值,SQL语句如下:
SELECT month,
SUM(amount) AS month_amount,
AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS moving_average
FROM all_sales
where year = 2003
GROUP BY month
ORDER BY month;
对移动平均值部分AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)解析如下:
- AVG(SUM(amount))内部的sum(amount)计算月销量和,外部的avg()计算平均值。
- ORDER BY month 按月份对查询读取的记录进行排序(这是必须的,因为只有排序后才能做累积或前后求平均值)。
- ROWS BETWEEN 3 PRECEDING AND CURRENT ROW定义了窗口的起点为当前记录的前3条记录,窗口的终点为当前记录。
计算中心平均值
计算当前月份前、后各一个月的销量移动平均值,SQL语句如下:
SELECT month,
SUM(amount) AS month_amount,
AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_average
FROM all_sales
where year = 2003
GROUP BY month
ORDER BY month;
对中心平均值部分AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)解析如下:
- AVG(SUM(amount))内部的sum(amount)计算月销量和,外部的avg()计算平均值。
- ORDER BY month 按月份对查询读取的记录进行排序(这是必须的,因为只有排序后才能做累积或前后求平均值)。
- ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING定义了窗口的起点是当前记录之前的那条记录,窗口的终点是当前记录之后的那条记录。
窗口第一条和最后一条记录
FIRST_VALUE()和LAST_VALUE()函数可用于获取窗口中的第一行和最后一行数据,如,可用于获取当前月前一个月和后一个月的销量:
SELECT month,
SUM(amount) AS month_amount,
FIRST_VALUE(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS pre_month_amount,
LAST_VALUE(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS next_month_amount
FROM all_sales
where year = 2003
GROUP BY month
ORDER BY month;
其中,窗口定义了起点为前一个月终点为后一个月,故而first_value(sum(amount))为前一个月销量而last_value()为后一个月销量。
小学生之Oracle分析函数的更多相关文章
- Oracle分析函数入门
一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计 ...
- [转]oracle分析函数Rank, Dense_rank, row_number
oracle分析函数Rank, Dense_rank, row_number 分析函数2(Rank, Dense_rank, row_number) 目录 ==================== ...
- [转]oracle 分析函数over
oracle 分析函数over 分析函数(OVER) 目录: =============================================== 1.Oracle分析函数简介 2. O ...
- oracle分析函数与over()(转)
文章参考:http://blog.csdn.net/haiross/article/details/15336313 -- Oracle分析函数入门-- 分析函数是什么? 分析函数是Oracle专门用 ...
- Oracle分析函数 — rank, dense_rank, row_number用法
本文通过例子演示了Oracle分析函数 —— rank, dense_rank, row_number的用法. //首先建score表 create table score( course nva ...
- 常用Oracle分析函数详解 [http://www.cnblogs.com/benio/archive/2011/06/01/2066106.html]
学习步骤:1. 拥有Oracle EBS demo 环境 或者 PROD 环境2. copy以下代码进 PL/SQL3. 配合解释分析结果4. 如果网页有点乱请复制到TXT中查看 /*假设一个经理 ...
- oracle分析函数技术详解(配上开窗函数over())
一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计 ...
- Oracle分析函数——函数列表
--------------聚合函数 SUM :该函数计算组中表达式的累积和 MIN :在一个组中的数据窗口中查找表达式的最小值 MAX :在一个组中的数据窗口中查找表达式的最大值 AVG :用于计算 ...
- 强大的oracle分析函数
转载:https://www.cnblogs.com/benio/archive/2011/06/01/2066106.html 学习步骤:1. 拥有Oracle EBS demo 环境 或者 PRO ...
随机推荐
- 如何遍历json属性和动态添加属性
var person= { name: 'zhangsan', pass: '123' , 'sni.ni' : 'sss', hello:function (){ for(var i=0;i< ...
- 路由器to路由器
本文主要介绍一个主路由器连接两个子路由器的方法: 主路由器: 设置主路由器的开始ip地址为192.168.1.100,结束ip地址为192.168.150: 子路由器A: 第一步:LAN设置 第二步: ...
- Extjs之rowEditing编辑状态时列不对齐
Extjs在使用rowEditing的时候,会在每一列加上editor属性,表示当处于编辑状态时这一列的值是什么类型的,后突然发现在rowEditing处于编辑状态时每一列的宽度边框了,如果列数非常多 ...
- SCJP_104——题目分析(2)
3. public class IfTest{ public static void main(String args[]){ int x=3; int y=1; if(x=y) System.out ...
- net Random 随机数重复的问题
在实际项目中不仅需要随机产生密码字符串,还要一次生成多个.我把生成随机字符串的方法放到for循环中,问题出现了. 生成的字符串,会重复. 经过多方查证,原因在代码. //使用与系统时间相关的种子 Ra ...
- 在同个工程中使用 Swift 和 Objective-C(Swift 2.0更新)-b
本节包含内容: Mix and Match 概述(Mix and Match Overview) 在同个应用的 target 中导入(Importing Code from Within the Sa ...
- 变身windows达人,用运行命令直接启动所有应用程序
先看一下效果 在”运行“输入QQ,敲回车即打开登录窗口,相当于双击QQ登录快捷方式,对于码农.电脑一族这是不是一件高逼格,很酷的事?你甚至可以将任何你想设置命令启动的程序用该方式启动,比如敲chrom ...
- LINUX BASH SHELL,小小学习一下
注意点要注意的: 整数运算一般通过 let 和 expr 这两个指令来实现,如对变量 x 加 1 可以写作:let "x = $x + 1" 或者 x=`expr $x + 1` ...
- Detours简介 (拦截x86机器上的任意的win32 API函数)
Detours 当然是用detours,微软明显高腾讯一筹,同上,至今没失败过.写这种HOOK一定要再写个测试程序,不要直接HOOK你的目的程序,例如QQ,因为这样不方面更灵活的测试.说明一下:Det ...
- [Delphi]检查URL是否有效的函数
function CheckUrl(url: string): boolean; var hSession, hfile, hRequest: hInternet; dwindex, dwcodele ...