`

Oracle高级查询之OVER (PARTITION BY ..)

阅读更多
为了方便大家学习和测试,所有的例子都是在Oracle自带用户Scott下建立的。


注:标题中的红色order by是说明在使用该方法的时候必须要带上order by。

一、rank()/dense_rank() over(partition by ...order by ...)

现在客户有这样一个需求,查询每个部门工资最高的雇员的信息,相信有一定oracle应用知识的同学都能写出下面的SQL语句:

select e.ename, e.job, e.sal, e.deptno 
  from scott.emp e, 
       (select e.deptno, max(e.sal) sal from scott.emp e group by e.deptno) me 
where e.deptno = me.deptno 
   and e.sal = me.sal; 
在满足客户需求的同时,大家应该习惯性的思考一下是否还有别的方法。这个是肯定的,就是使用本小节标题中rank() over(partition by...)或dense_rank() over(partition by...)语法,SQL分别如下:

select e.ename, e.job, e.sal, e.deptno 
  from (select e.ename, 
               e.job, 
               e.sal, 
               e.deptno, 
               rank() over(partition by e.deptno order by e.sal desc) rank 
          from scott.emp e) e 
where e.rank = 1; 
select e.ename, e.job, e.sal, e.deptno 
  from (select e.ename, 
               e.job, 
               e.sal, 
               e.deptno, 
               dense_rank() over(partition by e.deptno order by e.sal desc) rank 
          from scott.emp e) e 
where e.rank = 1; 
为什么会得出跟上面的语句一样的结果呢?这里补充讲解一下rank()/dense_rank() over(partition by e.deptno order by e.sal desc)语法。
over:  在什么条件之上。
partition by e.deptno:  按部门编号划分(分区)。
order by e.sal desc:  按工资从高到低排序(使用rank()/dense_rank() 时,必须要带order by否则非法)
rank()/dense_rank():  分级
整个语句的意思就是:在按部门划分的基础上,按工资从高到低对雇员进行分级,“级别”由从小到大的数字表示(最小值一定为1)。

那么rank()和dense_rank()有什么区别呢?
rank():  跳跃排序,如果有两个第一级时,接下来就是第三级。
dense_rank():  连续排序,如果有两个第一级时,接下来仍然是第二级。

小作业:查询部门最低工资的雇员信息。

二、min()/max() over(partition by ...)

现在我们已经查询得到了部门最高/最低工资,客户需求又来了,查询雇员信息的同时算出雇员工资与部门最高/最低工资的差额。这个还是比较简单,在第一节的groupby语句的基础上进行修改如下:

select e.ename, 
         e.job, 
         e.sal, 
         e.deptno, 
         e.sal - me.min_sal diff_min_sal, 
         me.max_sal - e.sal diff_max_sal 
    from scott.emp e, 
         (select e.deptno, min(e.sal) min_sal, max(e.sal) max_sal 
            from scott.emp e 
           group by e.deptno) me 
   where e.deptno = me.deptno 
   order by e.deptno, e.sal; 
上面我们用到了min()和max(),前者求最小值,后者求最大值。如果这两个方法配合over(partition by ...)使用会是什么效果呢?大家看看下面的SQL语句:

select e.ename, 
       e.job, 
       e.sal, 
       e.deptno, 
       nvl(e.sal - min(e.sal) over(partition by e.deptno), 0) diff_min_sal, 
       nvl(max(e.sal) over(partition by e.deptno) - e.sal, 0) diff_max_sal 
  from scott.emp e; 
这两个语句的查询结果是一样的,大家可以看到min()和max()实际上求的还是最小值和最大值,只不过是在partition by分区基础上的。

小作业:如果在本例中加上order by,会得到什么结果呢?

三、lead()/lag() over(partition by ... order by ...)

中国人爱攀比,好面子,闻名世界。客户更是好这一口,在和最高/最低工资比较完之后还觉得不过瘾,这次就提出了一个比较变态的需求,计算个人工资与比自己高一位/低一位工资的差额。这个需求确实让我很是为难,在groupby语句中不知道应该怎么去实现。不过。。。。现在我们有了over(partition by ...),一切看起来是那么的简单。如下:

select e.ename, 
       e.job, 
       e.sal, 
       e.deptno, 
       lead(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lead_sal, 
       lag(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lag_sal, 
       nvl(lead(e.sal) over(partition by e.deptno order by e.sal) - e.sal, 
           0) diff_lead_sal, 
       nvl(e.sal - lag(e.sal) over(partition by e.deptno order by e.sal), 0) diff_lag_sal 
  from scott.emp e;  
看了上面的语句后,大家是否也会觉得虚惊一场呢(惊出一身冷汗后突然鸡冻起来,这样容易感冒)?我们还是来讲解一下上面用到的两个新方法吧。
lead(列名,n,m):  当前记录后面第n行记录的<列名>的值,没有则默认值为m;如果不带参数n,m,则查找当前记录后面第一行的记录<列名>的值,没有则默认值为null。
lag(列名,n,m):  当前记录前面第n行记录的<列名>的值,没有则默认值为m;如果不带参数n,m,则查找当前记录前面第一行的记录<列名>的值,没有则默认值为null。

下面再列举一些常用的方法在该语法中的应用(注:带order by子句的方法说明在使用该方法的时候必须要带order by):

select e.ename, 
       e.job, 
       e.sal, 
       e.deptno, 
       first_value(e.sal) over(partition by e.deptno) first_sal, 
       last_value(e.sal) over(partition by e.deptno) last_sal, 
       sum(e.sal) over(partition by e.deptno) sum_sal, 
       avg(e.sal) over(partition by e.deptno) avg_sal, 
       count(e.sal) over(partition by e.deptno) count_num, 
       row_number() over(partition by e.deptno order by e.sal) row_num 
  from scott.emp e; 

重要提示:大家在读完本片文章之后可能会有点误解,就是OVER (PARTITION BY ..)比GROUP BY更好,实际并非如此,前者不可能替代后者,而且在执行效率上前者也没有后者高,只是前者提供了更多的功能而已,所以希望大家在使用中要根据需求情况进行选择。Oracle高级查询之OVER (PARTITION BY ..)
分享到:
评论

相关推荐

    Oracle查询中OVER (PARTITION BY ..)用法

    主要介绍了Oracle查询中OVER (PARTITION BY ..)用法,内容和代码大家参考一下。

    Oracle 语法之 OVER (PARTITION BY ..) 及开窗函数(转载)

    Oracle 语法之 OVER (PARTITION BY ..) 及开窗函数(转载),这个命令很实用,对于分析人员经常用到。

    Oracle中rank,over partition函数的使用方法

    这些排列函数提供了定义一个集合(使用 PARTITION 子句),然后根据某种排序方式对这个集合内的元素进行排列的能力,下面以scott用户的emp表为例来说明rank over partition如何使用。 1)查询员工薪水并连续求和 ...

    oracle分析函数在BI分析中应用事例

    1、 结构:聚合函数()over( partition by 字段1,字段2,字段3 order by 字段 desc/asc range between 数值/date preceding/flowing and 数值/date preceding/flowing) 聚合函数可以是:sum,count,avg,max,min,...

    oracle函数介绍(6) 著名函数之分析函数.doc

    SELECT col, AVG(value) OVER(PARTITION BY col ORDER BY col) FROM tmp1 ORDER BY col; 2、SUM ( [ DISTINCT | ALL ] expr ) OVER ( analytic_clause ) 例如: --聚合函数 SELECT col, sum(value) FROM tmp1 ...

    oracle分组查询

    oracle分组查询数据 select BFMBIGNAME,projectaddress,...from(select BFMBIGNAME,projectaddress,BFMSMALLNAME,row_number() over (partition by BFMBIGNAME order by REGISTERDATE) id from Projectinfo) where id;

    oracle常用sql查询语句部分集合(图文)

    select * from (select deptno,ename,sal,dense_rank() over(partition by deptno order by sal desc) a from scott.emp) where a&lt;=3 order by deptno asc,sal desc ; 结果: –rank()分析函数(运行结果与上语句...

    oracle函数介绍(5) 分析函数简述.doc

    第五篇 分析函数简述 ... Partition 子句:Partition by exp1[ ,exp2]... Partition没啥说的,功能强大参数少,主要用于分组,可以理解成select中的group by。不过它跟select语句后跟的group by 子句并不冲突。

    oracle中rownum和row_number()

    row_number()over(partition by col1 order by col2)表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部排序后的顺序编号(组内连续的唯一的)。 与rownum的区别在于:使用rownum进行排序的...

    ORACLE分析函数

    sum(sal) over (partition by deptno order by ename) 按部门“连续”求总和 sum(sal) over (partition by deptno) 按部门求总和 sum(sal) over (order by deptno,ename) 不按部门“连续”求总和 sum(sal) over () ...

    oracle函数介绍(7) 非著名函数之分析函数.doc

    1、CUME_DIST() OVER([partition_clause] order_by_clause) 返回该行在分组序列中的相对位置,返回值介于0到1之间。注意哟,如果order by的列是desc,则该分组内最大的行返回列值1,如果order by为asc,则该分组内...

    oracle去重复

    oracle去重复 ROW_NUMBER() over(partition by 列名1 order by 列名2)

    Oracle分区技术介绍

    For example, a query that requests data generated in the month of October 1994 can scan just the rows stored in the October 1994 partition, rather than rows generated over years of activity....

    oracle常用分析函数与聚合函数的用法

     rank ( ) over ([partition by col] order by col ) dense_rank ( ) over ([partition by col] order by col ) rownumber ( ) over ( [partition by col] order by col ) rank() 是排名的函数,该函数组内...

    oracle的row_numer()函数的使用

    介绍了 row_number() over(order by column asc) 函数和 row_number() over(partition by column1 order by column2 asc) 的使用实例和方法

    mysql代码-查询每天前三条数据 按照交易价格大到小排序 相当于模拟Oracle Row_Number() OVER (partition by date ORDER BY pay desc)

    mysql代码-查询每天前三条数据 按照交易价格大到小排序 相当于模拟Oracle Row_Number() OVER (partition by date ORDER BY pay desc)

    Oracle开发之分析函数总结

    代码如下:Sum() Over ([Partition by ] [Order by ])   Sum() Over ([Partition by ] [Order by ]   Rows Between Preceding And Following)   Sum() Over ([Partition by ] [Order by ]  Rows Between ...

Global site tag (gtag.js) - Google Analytics