-- Start

说起 Oracle 分析函数,可以用很好很强大来形容。这项功能特别适用于各种统计查询,这些查询用通常的SQL很难实现,或者根本就无发实现。首先,我们从一个简单的例子开始,来一步一步揭开它神秘的面纱,请看下面的SQL:

CREATE TABLE EMPLOY
(NAME    VARCHAR2(10),  --姓名DEPT    VARCHAR2(10),  --部门SALARY  NUMBER         --工资
);INSERT INTO EMPLOY VALUES ('张三','市场部',4000);
INSERT INTO EMPLOY VALUES ('赵红','技术部',2000);
INSERT INTO EMPLOY VALUES ('李四','市场部',5000);
INSERT INTO EMPLOY VALUES ('李白','技术部',5000);
INSERT INTO EMPLOY VALUES ('王五','市场部',NULL);
INSERT INTO EMPLOY VALUES ('王蓝','技术部',4000);SELECTROW_NUMBER() OVER(ORDER BY SALARY) AS 序号,NAME                               AS 姓名,DEPT                               AS 部门,SALARY                             AS 工资
FROM EMPLOY;查询结果如下:序号       姓名       部门      工资
1          赵红       技术部    2000
2          张三       市场部    4000
3          王蓝       技术部    4000
4          李四       市场部    5000
5          李白       技术部    5000
6          王五       市场部    (null)

看到上面的ROW_NUMBER() OVER()了吗?很多人非常不理解,怎么两个函数能这么写呢?甚至有人怀疑上面的SQL语句是不是真的能执行。其实,ROW_NUMBER是个函数没错,它的作用从它的名字也可以看出来,就是给查询结果集编号。但是,OVER并不是一个函数,而是一个分析语句,它的作用是定义一个作用域(或者可以说是结果集),OVER前面的函数只对OVER定义的结果集起作用。怎么样,不明白?没关系,我们后面还会详细介绍。

从上面的SQL我们可以看出,典型的 Oracle 在线分析处理的格式包括两部分:函数部分OVER分析语句部分。那么,函数部分可以有哪些函数呢?如下:

ROW_NUMBER           给查询结果集编行号
RANK                给查询结果集编排名
DENSE_RANK          给查询结果集编排名
MIN                 求最小值
MAX                 求最大值
AVG                 求平均值
SUM                 求总和
COUNT               求结果集行数
FIRST_VALUE         求最小值
LAST_VALUE          求最大值
FIRST               求最小值, 配合 DENSE_RANK 使用
LAST                求最大值, 配合 DENSE_RANK 使用
LAG                 向下偏移
LEAD                向上偏移
LISTAGG             连接列
NTILE               平分组
NTH_VALUE           返回第 n 行的值
VARIANCE            方差
VAR_POP             总体方差
VAR_SAMP            样本方差
STDDEV              标准偏差
STDDEV_POP          总体标准偏差
STDDEV_SAMP         样本标准偏差
CORR                协方差
COVAR_POP           总体协方差
COVAR_SAMP          样本协方差
CUME_DIST           计算积分分布
PERCENT_RANK        和 CUME_DIST 类似
PERCENTILE_CONT     计算值的连续分布模型
PERCENTILE_DISC     计算值的不连续分布模型
RATIO_TO_REPORT     计算比率
REGR_SLOPE          线性回归
REGR_INTERCEPT      线性回归
REGR_COUNT          线性回归
REGR_R2             线性回归
REGR_AVGX           线性回归
REGR_AVGY           线性回归
REGR_SXX            线性回归
REGR_SYY            线性回归
REGR_SXY            线性回归

上面这些函数的作用,我会在后面逐步给大家介绍,大家可以根据函数名猜测一下函数的作用。

假设我想在不改变上面语句查询结果的情况下,追加对部门员工的平均工资和全体员工的平均工资的查询,怎么办呢?用通常的SQL很难查询,但是用分析函数则非常简单,如下SQL所示:

SELECTROW_NUMBER() OVER(ORDER BY DEPT, SALARY)             AS 序号,ROW_NUMBER() OVER(PARTITION BY DEPT ORDER BY SALARY) AS 部门序号,NAME                                                 AS 姓名,DEPT                                                 AS 部门,SALARY                                               AS 工资,AVG(SALARY) OVER(PARTITION BY DEPT)                  AS 部门平均工资,AVG(SALARY) OVER()                                   AS 全员平均工资
FROM EMPLOY;查询结果如下:序号       部门序号     姓名       部门      工资       部门平均工资     全员平均工资
1            1          张三       市场部    4000       4500             4000
2            2          李四       市场部    5000       4500             4000
3            3          王五       市场部    (null)     4500             4000
4            1          赵红       技术部    2000       3666.67          4000
5            2          王蓝       技术部    4000       3666.67          4000
6            3          李白       技术部    5000       3666.67          4000

请注意序号和部门序号之间的区别,我们在查询部门序号的时候,在OVER表达式中多了两个子句,分别是 PARTITION BYORDER BY。它们有什么作用呢?在介绍它们的作用之前,我们先来回顾一下OVER的作用,还记得吗?

OVER是一个分析语句,它的作用是定义一个作用域(或者可以说是结果集),OVER前面的函数只对OVER定义的结果集起作用。

ORDER BY的作用大家非常熟悉,用来对结果集排序。PARTITION BY的作用其实也很简单,和GROUP BY的作用相同,用来对结果集分组。

到此为止,大家应该对分析函数的套路有一定的了解和体会了吧。大家看一下上面SQL的结果集,发现王五的工资是null,当我们按工资排序时,null被放到最后,我们想把 null 放在前边该怎么办呢?使用NULLS FIRST关键字即可,默认是NULLS LAST,请看下面的SQL:

SELECTROW_NUMBER() OVER(ORDER BY SALARY DESC NULLS FIRST)    AS RN,RANK() OVER(ORDER BY SALARY DESC NULLS FIRST)          AS RK,DENSE_RANK() OVER(ORDER BY SALARY DESC NULLS FIRST)    AS D_RK,NAME                                                   AS 姓名,DEPT                                                   AS 部门,SALARY                                                 AS 工资
FROM EMPLOY;查询结果如下:RN  RK   D_RK     姓名       部门       工资
1     1     1     王五       市场部    (null)
2     2     2     李四       市场部    5000
3     2     2     李白       技术部    5000
4     4     3     张三       市场部    4000
5     4     3     王蓝       技术部    4000
6     6     4     赵红       技术部    2000

请注意ROW_NUMBER和RANK之间的区别,RANK是等级,排名的意思,李四和李白的工资都是5000,他们并列排名第二。张三和王蓝的工资都是4000,怎么RANK函数的排名是第四,而DENSE_RANK的排名是第三呢?这正是这两个函数之间的区别。由于有两个第二名,所以RANK函数默认没有第三名。

现在又有个新问题,假设让你查询一下每个员工的工资以及工资小于他的所有员工的平均工资,该怎么办呢?怎么?没听明白问题?不要紧,请看下面的SQL:

SELECTNAME                                                                AS 姓名,SALARY                                                              AS 工资,SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)         AS 小于本人工资的总额,SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)         AS 大于本人工资的总额,SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS 工资总额1,SUM(SALARY) OVER()                                                  AS 工资总额2
FROM EMPLOY;查询结果如下:姓名       工资       小于本人工资的总额  大于本人工资的总额    工资总额1     工资总额2
王五       (null)     (null)              20000                 20000         20000
赵红       2000       2000                20000                 20000         20000
张三       4000       6000                18000                 20000         20000
王蓝       4000       10000               14000                 20000         20000
李四       5000       15000               10000                 20000         20000
李白       5000       20000               5000                  20000         20000

上面SQL 中的OVER部分出现了一个ROWS子句,我们先来看一下ROWS子句的结构:

ROWS BETWEEN <上限条件> AND <下限条件>其中“上限条件”可以是如下关键字:
UNBOUNDED PRECEDING
<number>  PRECEDING
CURRENT ROW“下线条件”可以是如下关键字:
CURRENT ROW
<number> FOLLOWING
UNBOUNDED FOLLOWING

注意,以上关键字都是相对当前行的,UNBOUNDED PRECEDING表示当前行前面的所有行,也就是说没有上限;<number> PRECEDING表示从当前行开始到它前面的<number>行为止,例如,number=2,表示的是当前行前面的2行;CURRENT ROW表示当前行。至于其它两个关键字,我想,不用我说,你也应该知道了吧。如果你还不明白,请仔细分析上面SQL的查询结果。

OVER 分析语句还可以有个子句,那就是RANGE,它的使用方式和ROWS十分相似,或者说一模一样,作用也差多不,不过有点区别,如下所示:

RANGE BETWEEN <上限条件>AND <下限条件>

其中的<上限条件>、<下限条件>和ROWS一模一样,如下的SQL演示它们之间的区别:

DELETE FROM EMPLOY;
INSERT INTO EMPLOY VALUES ('张三','市场部',2000);
INSERT INTO EMPLOY VALUES ('赵红','技术部',2400);
INSERT INTO EMPLOY VALUES ('李四','市场部',3000);
INSERT INTO EMPLOY VALUES ('李白','技术部',3200);
INSERT INTO EMPLOY VALUES ('王五','市场部',4000);
INSERT INTO EMPLOY VALUES ('王蓝','技术部',5000);   SELECTNAME                                                                              AS 姓名,DEPT                                                                              AS 部门,SALARY                                                                            AS 工资,FIRST_VALUE(SALARY IGNORE NULLS) OVER(PARTITION BY DEPT)                  AS 部门最低工资,NTH_VALUE(SALARY, 2) OVER(PARTITION BY DEPT)                          AS 部门倒数第二工资,LAST_VALUE(SALARY RESPECT NULLS) OVER(PARTITION BY DEPT)                  AS 部门最高工资,SUM(SALARY) OVER(ORDER BY SALARY ROWS BETWEEN 1 PRECEDING  AND 1 FOLLOWING)     AS "ROWS", SUM(SALARY) OVER(ORDER BY SALARY RANGE BETWEEN 500 PRECEDING AND 500 FOLLOWING) AS "RANGE"
FROM EMPLOY;查询结果如下:  姓名    部门      工资    部门最低工资    部门倒数第二工资   部门最高工资       ROWS    RANGE
张三    市场部    2000    2000            3000               4000               4400    4400
赵红    技术部    2400    3200            5000               2400               7400    4400
李四    市场部    3000    2000            3000               4000               8600    6200
李白    技术部    3200    3200            5000               2400               10200   6200
王五    市场部    4000    2000            3000               4000               12200   4000
王蓝    技术部    5000    3200            5000               2400               9000    5000

上面SQL的RANGE子句的作用是定义一个工资范围,这个范围的上限是当前行的工资-500,下限是当前行工资+500。例如:李四的工资是3000,所以上限是3000-500=2500,下限是3000+500=3500,那么有谁的工资在2500-3500这个范围呢?只有李四和李白,所以RANGE列的值就是3000(李四)+3200(李白)=6200。以上就是ROWS和RANGE得区别。

上面的 SQL 还用到了FIRST_VALUE,NTH_VALUE 和 LAST_VALUE 三个函数,它们的作用也非常简单,用来求OVER定义集合的最小值,第 n 行的值和最大值。值得注意的是这两个函数有个关键字,IGNORE NULLS 或 RESPECT NULLS,它们的作用正如它们的名字一样,用来忽略NULL值和考虑NULL值。

还有两个函数我们没有介绍,LAGLEAD,这两个函数的功能非常强大,请看下面SQL:

SELECTNAME                                                     AS 姓名,SALARY                                                   AS 工资,LAG(SALARY,0) OVER(ORDER BY SALARY)                      AS LAG0,LAG(SALARY) OVER(ORDER BY SALARY)                        AS LAG1,LAG(SALARY,2) OVER(ORDER BY SALARY)                      AS LAG2,LAG(SALARY,3 ,0) IGNORE NULLS OVER(ORDER BY SALARY)      AS LAG3,LAG(SALARY,4, -1) RESPECT NULLS OVER(ORDER BY SALARY)    AS LAG4,LEAD(SALARY) OVER(ORDER BY SALARY)                       AS LEAD
FROM EMPLOY;查询结果如下:姓名       工资       LAG0      LAG1      LAG2      LAG3      LAG4      LEAD
张三       2000       2000      (null)   (null)       0       -1        2400
赵红       2400       2400       2000    (null)       0       -1        3000
李四       3000       3000       2400     2000       0        -1        3200
李白       3200       3200       3000     2400       2000     -1        4000
王五       4000       4000       3200     3000       2400     2000      5000
王蓝       5000       5000       4000     3200       3000     2400      (null)

我们先来看一下LAG和 LEAD 函数的声明,如下:

LAG(表达式或字段,偏移量, 默认值) IGNORE NULLS或RESPECT NULLS

LAG是向下偏移,LEAD是向上偏移,大家看一下上面SQL的查询结果就一目了然了。

到此为止,有关Oracle 分析函数的所有知识都介绍给大家了,下面我们再次回顾一下Oracle 分析函数的组成部分,如下:

分析函数 OVER(PARTITIONBY子句 ORDER BY 子句 ROWS或RANGE子句)

要想熟练掌握这些知识还需要一定的时间和练习,一旦你掌握了,你将拥有一项绝世武学,可以纵横 Oracle。

-- 更多参见:Oracle SQL 精萃

-- 声明:转载请注明出处

-- Last Edited on 2015-02-28

-- Created by ShangBo on 2014-12-19

-- End

Oracle 分析函数相关推荐

  1. Oracle分析函数五——统计分析函数

    Oracle 分析函数--统计分析函数 方差和标准差:     样本中各数据与样本平均数的差的平方和的平均数叫做样本方差:样本方差的算术平方根叫做样本标准差.样本方差和样本标准差都是衡量一个样本波动大 ...

  2. oracle 四分位函数,Oracle分析函数四——函数RANK,DENSE_RANK,FIRST,LAST…

    Oracle 分析函数--函数RANK,DENSE_RANK,FIRST,LAST- RANK 功能描述:根据 ORDER BY 子句中表达式的值,从查询返回的每一行,计算它们与其它行的相对位置.组内 ...

  3. 【分析函数】Oracle分析函数之LAG和LEAD

    [分析函数]Oracle分析函数之LAG和LEAD Lag和Lead函数可以在一次查询中取出同一字段的前N行的数据和后N行的值.这种操作可以使用对相同表的表连接来实现,不过使用LAG和LEAD有更高的 ...

  4. oracle 数据分析函数,ORACLE分析函数(一)

    ORACLE分析函数(1) 分析函数式ORACLE提供的用来进行数据统计的强有力工具,与我们常用的聚合函数具有一些相似性,但又完全不同.聚合函数,首先会将数据进行分组,然后对每一组数据进行运算,如求和 ...

  5. Oracle分析函数巧妙使用

    在 Oracle中使用Sql必须弄懂分析函数 Oracle开发专题之:分析函数(OVER) 1 Oracle开发专题之:分析函数2(Rank, Dense_rank, row_number) 6 Or ...

  6. Oracle 分析函数--Row_Number()

    row_number() over ([partition by col1] order by col2) ) as 别名 表示根据col1分组,在分组内部根据 col2排序 而这个"别名& ...

  7. Oracle分析函数——函数列表

    --------------聚合函数 SUM :该函数计算组中表达式的累积和 MIN :在一个组中的数据窗口中查找表达式的最小值 MAX :在一个组中的数据窗口中查找表达式的最大值 AVG :用于计算 ...

  8. Oracle分析函数三——SUM,AVG,MIN,MAX,COUNT

    Oracle 分析函数--SUM,AVG,MIN,MAX,COUNT SUM 功能描述:该函数计算组中表达式的累积和. SAMPLE :下例计算同一经理下员工的薪水累积值 MIN 功能描述:在一个组中 ...

  9. oracle 分析函数、GROUPING函数

    分析函数 over(Partition by...) 一个超级牛皮的ORACLE特有函数.天天都用ORACLE,用了快2年了.最近才接触到这个功能强大而灵活的函数.真实惭愧啊!oracle的分析函数o ...

  10. Oracle分析函数四——函数RANK,DENSE_RANK,FIRST,LAST…

    Oracle分析函数--函数RANK,DENSE_RANK,FIRST,LAST- RANK 功能描述:根据ORDER BY子句中表达式的值,从查询返回的每一行,计算它们与其它行的相对位置.组内的数据 ...

最新文章

  1. 拉格朗日乘数法学习笔记
  2. 谷歌发布android+8.2,谷歌Pixel 2代三款新机齐曝光:骁龙835+Android 8.0
  3. 并行计算机架构_计算机科学组织| 并行处理
  4. 注意html的语言编码charset,HTML编码
  5. SQL Server中 sysobjects、syscolumns、systypes
  6. vue学习笔记-6-样式绑定
  7. 2020 年前端技术发展盘点
  8. m3u8视频通用下载器
  9. 我努力了18年,不是为了和你一起喝咖啡姐妹篇
  10. 量化投资的Python入门,也很适合机器学习Python入门
  11. 进程和线程常见的19个问题
  12. 阿里云ACP认证之云服务器ECS知识整理(考题占比 31%)
  13. 威尔士和英格兰同属英国,但为啥还要在世界杯上进行PK?
  14. C++ 四种cast 详解
  15. oracle 控制文件 dump,将控制文件dump出来研究下内容
  16. 绝对隐私:华为公司员工待遇全面揭秘(转)
  17. Unity新手入门与进阶学习书籍与教程推荐
  18. python 实现简单的session登录
  19. 漫漫长夜无限服务器断开,漫漫长夜崩溃问题解决方法 | 手游网游页游攻略大全...
  20. 怎样用HTML做一份精美的简历(html5+css)

热门文章

  1. maple里面怎么搜索_教你用Maple全局优化工具寻找最值
  2. 锐捷 重启计算机,提示“重启计算机后才能使用锐捷客户端”常用解决方法
  3. Python黑客编程入门教程
  4. 职称计算机考试excel内容,2020年职称计算机考试EXCEL试题练习
  5. 跨交换机的VLAN 部署
  6. java高级能力_java高级技术工程师该具备哪些能力?
  7. Sentence2vec
  8. 计算机辅助几何设计知识点,计算机辅助几何设计
  9. OKR怎么写?100个OKR案例模板
  10. 虚拟机安装教程win7_VMware15虚拟机软件安装教程