Oracle高级查询之OVER (PARTITION BY ..)
admin
2023-05-09 21:01:47
0

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

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

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

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

[sql] view plaincopy

  1. select e.ename, e.job, e.sal, e.deptno  

  2.   from scott.emp e,  

  3.        (select e.deptno, max(e.sal) sal from scott.emp e group by e.deptno) me  

  4.  where e.deptno = me.deptno  

  5.    and e.sal = me.sal;  

在满足客户需求的同时,大家应该习惯性的思考一下是否还有别的方法。这个是肯定的,就是使用本小节标题中rank() over(partition by...)或dense_rank() over(partition by...)语法,SQL分别如下:

[sql] view plaincopy

  1. select e.ename, e.job, e.sal, e.deptno  

  2.   from (select e.ename,  

  3.                e.job,  

  4.                e.sal,  

  5.                e.deptno,  

  6.                rank() over(partition by e.deptno order by e.sal desc) rank  

  7.           from scott.emp e) e  

  8.  where e.rank = 1;  

[sql] view plaincopy

  1. select e.ename, e.job, e.sal, e.deptno  

  2.   from (select e.ename,  

  3.                e.job,  

  4.                e.sal,  

  5.                e.deptno,  

  6.                dense_rank() over(partition by e.deptno order by e.sal desc) rank  

  7.           from scott.emp e) e  

  8.  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语句的基础上进行修改如下:

[sql] view plaincopy

  1. select e.ename,  

  2.          e.job,  

  3.          e.sal,  

  4.          e.deptno,  

  5.          e.sal - me.min_sal diff_min_sal,  

  6.          me.max_sal - e.sal diff_max_sal  

  7.     from scott.emp e,  

  8.          (select e.deptno, min(e.sal) min_sal, max(e.sal) max_sal  

  9.             from scott.emp e  

  10.            group by e.deptno) me  

  11.    where e.deptno = me.deptno  

  12.    order by e.deptno, e.sal;  

上面我们用到了min()和max(),前者求最小值,后者求最大值。如果这两个方法配合over(partition by ...)使用会是什么效果呢?大家看看下面的SQL语句:

[sql] view plaincopy

  1. select e.ename,  

  2.        e.job,  

  3.        e.sal,  

  4.        e.deptno,  

  5.        nvl(e.sal - min(e.sal) over(partition by e.deptno), 0) diff_min_sal,  

  6.        nvl(max(e.sal) over(partition by e.deptno) - e.sal, 0) diff_max_sal  

  7.   from scott.emp e;  

这两个语句的查询结果是一样的,大家可以看到min()和max()实际上求的还是最小值和最大值,只不过是在partition by分区基础上的。

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

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

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

[sql] view plaincopy

  1. select e.ename,  

  2.        e.job,  

  3.        e.sal,  

  4.        e.deptno,  

  5.        lead(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lead_sal,  

  6.        lag(e.sal, 1, 0) over(partition by e.deptno order by e.sal) lag_sal,  

  7.        nvl(lead(e.sal) over(partition by e.deptno order by e.sal) - e.sal,  

  8.            0) diff_lead_sal,  

  9.        nvl(e.sal - lag(e.sal) over(partition by e.deptno order by e.sal), 0) diff_lag_sal  

  10.   from scott.emp e;   

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

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

[sql] view plaincopy

  1. select e.ename,  

  2.        e.job,  

  3.        e.sal,  

  4.        e.deptno,  

  5.        first_value(e.sal) over(partition by e.deptno) first_sal,  

  6.        last_value(e.sal) over(partition by e.deptno) last_sal,  

  7.        sum(e.sal) over(partition by e.deptno) sum_sal,  

  8.        avg(e.sal) over(partition by e.deptno) avg_sal,  

  9.        count(e.sal) over(partition by e.deptno) count_num,  

  10.        row_number() over(partition by e.deptno order by e.sal) row_num  

  11.   from scott.emp e;  


相关内容

热门资讯

以军士兵集体丢掉武器抗命,大喊... 据凤凰卫视报道,以色列国防军一军事基地7月30日发生士兵抗命事件,约120名士兵抗议指挥官做法,将武...
蒋成华任商务部副部长 国务院任免国家工作人员。任命蒋成华为商务部副部长。免去蒋成华的商务部国际贸易谈判副代表职务。
伊朗驻华大使:在军事威胁下,不... 新华社北京7月31日电(记者刁慧琳) 伊朗驻华大使法兹里7月28日表示,伊美回到谈判桌的前提是美国必...
伊朗革命卫队在霍尔木兹海峡击中... 当地时间31日,伊朗伊斯兰革命卫队发布声明称,革命卫队海军当天在霍尔木兹海峡击中并扣留了两艘违反禁令...
美媒:特朗普,遇到了一个更强硬... 据《纽约时报》7月29日报道,就在特朗普总统看似放弃战事升级计划几天后,美国再次与伊朗交火。上周末,...
女子做气管镜时不幸身亡,丈夫称... 7月29日,西安刘先生反映妻子在当地医院做支气管镜检查时死亡,看监控时发现医生疑有违规操作。刘先生表...
全网“帮卖西瓜”,然后呢? 近日,河南部分地区西瓜滞销的消息在网上热度很高。很多地方也伸出援手:有景区收购千斤西瓜、免费赠予游客...
美媒:乌克兰袭击伊朗船只,险引... 据《纽约时报》7月28日报道,据伊朗和西方官员称,伊朗曾考虑攻击乌克兰的一个港口,以报复乌克兰对一艘...
20年里,他只画美女,用东方风... 迈进KIM在上海的工作室,迎面是一整墙的美女们。她们像是刚从一场时髦的沙龙里退场,或倚或立,眉宇间是...
Google在港推出AI代理G... 观点网讯:7月29日,Google在香港推出AI代理Gemini Spark,该代理可全天候在后台运...