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

 
  1. SELECT
  2. ROW_NUMBER() OVER(ORDER BY SALARY) AS 序号,
  3. NAME AS 姓名,
  4. DEPT AS 部门,
  5. SALARY AS 工资
  6. FROM
  7. (
  8. --姓名    部门  工资
  9. VALUES
  10. ('张三','市场部',4000),
  11. ('赵红','技术部',2000),
  12. ('李四','市场部',5000),
  13. ('李白','技术部',5000),
  14. ('王五','市场部',NULL),
  15. ('王蓝','技术部',4000)
  16. ) AS EMPLOY(NAME,DEPT,SALARY);
  17. 查询结果如下:
  18. 序号       姓名       部门       工资
  19. 1     赵红       技术部    2000
  20. 2     张三       市场部    4000
  21. 3     王蓝       技术部    4000
  22. 4     李四       市场部    5000
  23. 5     李白       技术部    5000
  24. 6     王五       市场部    (null)

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

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

 
  1. ROW_NUMBER
  2. RANK
  3. DENSE_RANK
  4. FIRST_VALUE
  5. LAST_VALUE
  6. LAG
  7. LEAD
  8. COUNT
  9. MIN
  10. MAX
  11. AVG
  12. SUM

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

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

 
  1. SELECT
  2. ROW_NUMBER() OVER() AS 序号,
  3. ROW_NUMBER() OVER(PARTITION BY DEPT ORDER BY SALARY) AS 部门序号,
  4. NAME AS 姓名,
  5. DEPT AS 部门,
  6. SALARY AS 工资,
  7. AVG(SALARY) OVER(PARTITION BY DEPT) AS 部门平均工资,
  8. AVG(SALARY) OVER() AS 全员平均工资
  9. FROM
  10. (
  11. --姓名    部门  工资
  12. VALUES
  13. ('张三','市场部',4000),
  14. ('赵红','技术部',2000),
  15. ('李四','市场部',5000),
  16. ('李白','技术部',5000),
  17. ('王五','市场部',NULL),
  18. ('王蓝','技术部',4000)
  19. ) AS EMPLOY(NAME,DEPT,SALARY);
  20. 查询结果如下:
  21. 序号       部门序号       姓名       部门       工资       部门平均工资       全员平均工资
  22. 1            1          张三       市场部    4000       4500                     4000
  23. 2            2          李四       市场部    5000       4500                     4000
  24. 3            3          王五       市场部    (null)     4500                     4000
  25. 4            1          赵红       技术部    2000       3666                     4000
  26. 5            2          王蓝       技术部    4000       3666                     4000
  27. 6            3          李白       技术部    5000       3666                     4000

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

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

 

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

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

 
  1. SELECT
  2. ROW_NUMBER() OVER(ORDER BY SALARY desc NULLS FIRST) AS RN,
  3. RANK() OVER(ORDER BY SALARY desc NULLS FIRST) AS RK,
  4. DENSE_RANK() OVER(ORDER BY SALARY desc NULLS FIRST) AS D_RK,
  5. NAME AS 姓名,
  6. DEPT AS 部门,
  7. SALARY AS 工资
  8. FROM
  9. (
  10. --姓名    部门  工资
  11. VALUES
  12. ('张三','市场部',4000),
  13. ('赵红','技术部',2000),
  14. ('李四','市场部',5000),
  15. ('李白','技术部',5000),
  16. ('王五','市场部',NULL),
  17. ('王蓝','技术部',4000)
  18. ) AS EMPLOY(NAME,DEPT,SALARY);
  19. 查询结果如下:
  20. RN  RK   D_RK     姓名       部门       工资
  21. 1     1     1     王五       市场部    (null)
  22. 2     2     2     李四       市场部    5000
  23. 3     2     2     李白       技术部    5000
  24. 4     4     3     张三       市场部    4000
  25. 5     4     3     王蓝       技术部    4000
  26. 6     6     4     赵红       技术部    2000

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

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

 
  1. SELECT
  2. NAME AS 姓名,
  3. SALARY AS 工资,
  4. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS 小于本人工资的总额,
  5. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN  CURRENT ROW AND UNBOUNDED FOLLOWING) AS 大于本人工资的总额,
  6. SUM(SALARY) OVER(ORDER BY SALARY NULLS FIRST ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS 工资总额1,
  7. SUM(SALARY) OVER() AS 工资总额2
  8. FROM
  9. (
  10. --姓名    部门  工资
  11. VALUES
  12. ('张三','市场部',4000),
  13. ('赵红','技术部',2000),
  14. ('李四','市场部',5000),
  15. ('李白','技术部',5000),
  16. ('王五','市场部',NULL),
  17. ('王蓝','技术部',4000)
  18. ) AS EMPLOY(NAME,DEPT,SALARY);
  19. 查询结果如下:
  20. 姓名       工资       小于本人工资的总额    大于本人工资的总额    工资总额1     工资总额2
  21. 王五       (null)     (null)             20000              20000            20000
  22. 赵红       2000       2000               20000              20000            20000
  23. 张三       4000       6000               18000              20000            20000
  24. 王蓝       4000       10000              14000              20000            20000
  25. 李四       5000       15000              10000              20000            20000
  26. 李白       5000       20000              5000               20000            20000

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

 
  1. ROWS BETWEEN <上限条件> AND <下限条件>
  2. 其中“上限条件”可以是如下关键字:
  3. UNBOUNDED PRECEDING
  4. <number>  PRECEDING
  5. CURRENT ROW
  6. “下线条件”可以是如下关键字:
  7. CURRENT ROW
  8. <number> FOLLOWING
  9. UNBOUNDED FOLLOWING

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

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

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

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

 
  1. SELECT
  2. NAME AS 姓名,
  3. DEPT AS 部门,
  4. SALARY AS 工资,
  5. FIRST_VALUE(SALARY, 'IGNORE NULLS') OVER(PARTITION BY DEPT) AS 部门最低工资,
  6. LAST_VALUE(SALARY, 'RESPECT NULLS') OVER(PARTITION BY DEPT) AS 部门最高工资,
  7. SUM(SALARY) OVER(ORDER BY SALARY ROWS BETWEEN 1 PRECEDING  AND 1 FOLLOWING) AS ROWS,
  8. SUM(SALARY) OVER(ORDER BY SALARY RANGE BETWEEN 500 PRECEDING AND 500 FOLLOWING) AS RANGE
  9. FROM
  10. (
  11. --姓名    部门  工资
  12. VALUES
  13. ('张三','市场部',2000),
  14. ('赵红','技术部',2400),
  15. ('李四','市场部',3000),
  16. ('李白','技术部',3200),
  17. ('王五','市场部',4000),
  18. ('王蓝','技术部',5000)
  19. ) AS EMPLOY(NAME,DEPT,SALARY);
  20. 查询结果如下:
  21. 姓名       部门       工资       部门最低工资       部门最高工资       ROWS    RANGE
  22. 张三       市场部    2000       2000              4000             4400       4400
  23. 赵红       技术部    2400       2400              5000             7400       4400
  24. 李四       市场部    3000       2000              4000             8600       6200
  25. 李白       技术部    3200       2400              5000             10200     6200
  26. 王五       市场部    4000       2000              4000             12200     4000
  27. 王蓝       技术部    5000       2400              5000             9000       5000

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

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

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

 
  1. SELECT
  2. NAME AS 姓名,
  3. SALARY AS 工资,
  4. LAG(SALARY,0) OVER(ORDER BY SALARY) AS LAG0,
  5. LAG(SALARY) OVER(ORDER BY SALARY) AS LAG1,
  6. LAG(SALARY,2) OVER(ORDER BY SALARY) AS LAG2,
  7. LAG(SALARY,3,0,'IGNORE NULLS') OVER(ORDER BY SALARY) AS LAG3,
  8. LAG(SALARY,4,-1,'RESPECT NULLS') OVER(ORDER BY SALARY) AS LAG4,
  9. LEAD(SALARY) OVER(ORDER BY SALARY) AS LEAD
  10. FROM
  11. (
  12. --姓名    部门  工资
  13. VALUES
  14. ('张三','市场部',2000),
  15. ('赵红','技术部',2400),
  16. ('李四','市场部',3000),
  17. ('李白','技术部',3200),
  18. ('王五','市场部',4000),
  19. ('王蓝','技术部',5000)
  20. ) AS EMPLOY(NAME,DEPT,SALARY);
  21. 查询结果如下:
  22. 姓名       工资       LAG0      LAG1      LAG2      LAG3      LAG4      LEAD
  23. 张三       2000       2000      (null)   (null)       0       -1        2400
  24. 赵红       2400       2400       2000    (null)       0       -1        3000
  25. 李四       3000       3000       2400     2000       0        -1        3200
  26. 李白       3200       3200       3000     2400       2000     -1        4000
  27. 王五       4000       4000       3200     3000       2400     2000      5000
  28. 王蓝       5000       5000       4000     3200       3000     2400      (null)

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

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

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

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

函数 OVER(PARTITION BY 子句 ORDER BY 子句 ROWS或RANGE子句)

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

DB2 分组查询语句ROW_NUMBER() OVER() (转载)的更多相关文章

  1. oracle查询语句2【转载】

    本文使用的实例表结构与表的数据如下: scott.emp员工表结构如下:   SQL> DESC SCOTT.EMP; Name     Type         Nullable Defaul ...

  2. SQL Serever学习9——基础查询语句

    SQL语言概述 SQL是结构化查询语言(Structure Query Language),1974年提出,1979年被IBM实现,SQL语言已经成为关系型数据库的标准语言. 包括: DDL数据定义语 ...

  3. spring data jpa条件分组查询及分页

    原book对象 package com.shaying.domain; import javax.persistence.Column; import javax.persistence.Entity ...

  4. 在论坛中出现的比较难的sql问题:3(row_number函数 分组查询)

    原文:在论坛中出现的比较难的sql问题:3(row_number函数 分组查询) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所 ...

  5. 不同数据库oracle mysql SQL Server DB2 infomix sybase分页查询语句

    在不同数据库中的使用的分页查询语句: 当前页:currentpage 页大小:pagesize 1. Oracle数据库 select * from (select A.*,rownum rn fro ...

  6. mysql系列九、mysql语句执行过程及运行原理(分组查询和关联查询原理)

    一.背景介绍 了解一个sql语句的执行过程,了解一部分都做了什么,更有利于对sql进行优化,因为你知道它的每一个连接.where.分组.子查询是怎么运行的,都干了什么,才会知道怎么写是不合理的. 大致 ...

  7. SQL语句查询年龄分段分组查询

    此情况用于数据库中没有“年龄”这个字段,只有“出生日期”这个字段.先计算出“年龄”,在分组查询. 1.SELECT *, ROUND(DATEDIFF(CURDATE(), popBirthday)/ ...

  8. 转载《mysql 一》:mysql的select查询语句内在逻辑执行顺序

    原文:http://www.jellythink.com/archives/924 我的抱怨 我一个搞应用开发的,非要会数据库,这不是专门的数据库开发人员干的事么?话说,小公司也没有数 据库开发人员这 ...

  9. Oracle - 查询语句 - 分组函数

    /* 分组函数 不能再select子句中出现普通的列,除非这个列在group by中给出 所有的空值都会被分为一组 分组过滤 SELECT FROM WHERE GROUPBY HAVING ORDE ...

随机推荐

  1. three.js 曲线

    上几篇说了three.js的曲线,这篇来郭先生来说说three.js曲线,在线案例点击郭先生的博客查看. 1. 了解three.js曲线 之前已经说了一些three.js的几何体,这篇说一说three ...

  2. (6)webpack使用babel插件的使用

    为什么要使用babel插件? 首先要了解babel插件是干嘛的,随着js的语法规范发展,出现了越来越多的高级语法,但是使用webpack打包的时候,webpack并不能全部理解这些高级语法,需要我们使 ...

  3. ASP.NET Core静态文件处理源码探究

    前言     静态文件(如 HTML.CSS.图像和 JavaScript)等是Web程序的重要组成部分.传统的ASP.NET项目一般都是部署在IIS上,IIS是一个功能非常强大的服务器平台,可以直接 ...

  4. Burp Suite Spider Module - 网络爬虫模块

    Web application spdiering 和scanning 可以结合使用. Burp Suite 的Spider Module - Options 主要包含:Crawler Setting ...

  5. Python基础知识点:多进程的应用讲解

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:东哥IT笔记 现在很多CPU都支持多核,甚至是手机都已经开始支持多核 ...

  6. [日常摘要] -- zookeeper篇

    概览 设计目标 是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用 简介 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于Z ...

  7. Java7/8 中的 HashMap 和 ConcurrentHashMap

    Java7 HashMap  数组+链表 Java7 ConcurrentHashMap   Segment数组+HashEntry数组链表+ReenTrantLock分段锁 Java8 HashMa ...

  8. SPRING 阅读--JdkDynamicAopProxy

    一.简介 JdkDynamicAopProxy 代理类是spring 默认的JDK动态的代理类实现.它实现了Java 动态代理接口InvocationHandler接口和Spring定义的AopPro ...

  9. 解决node 运行接口 出现 Cannot destructure property `us` of 'undefined' or 'null'.

    出现 参数是 undefined or null 一.检查是否安装 body-parser server.js中是否引入 app.use(bodyParser.urlencoded({ extende ...

  10. PHP serialize() 函数

    serialize() 函数用于序列化对象或数组,并返回一个字符串.高佣联盟 www.cgewang.com serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型 ...