假设现在有一张学生表student,学生表中有姓名、分数、课程编号,现在我需要按照课程对学生的成绩进行排序。
select * from student
1. rank over ()可以实现对学生排名,特点是成绩相同的两名是并列,如下1 2 2 4 5
select name,
course,
rank() over(partition by course order by score desc) as rank
from student;
2. dense_rank()和rank over()很像,但学生成绩并列后并不会空出并列所占的名次,如下1 2 2 3 4
select name,
course,
dense_rank() over(partition by course order by score desc) as rank
from student;
3. row_number这个函数不需要考虑是否并列,那怕根据条件查询出来的数值相同也会进行连续排名
select name,
course,
row_number() over(partition by course order by score desc) as rank
from student;
答疑:
1. partition by用于给结果集进行分区。
2. partition by和group by有何区别?
partition by只是将原始数据进行名次排列(记录数不变)
group by是对原始数据进行聚合统计(记录数可能变少, 每组返回一条)
3. 使用rank over()的时候,空值是最大的,如果排序字段为null, 可能造成null字段排在最前面,影响排序结果。
可以这样: rank over(partition by course order by score desc nulls last)
为了方便大家学习和测试,所有的例子都是在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分析函数Rank、Dense_rank和row_number是用于处理数据集的高级工具,它们在数据库查询中发挥着关键作用,特别是在需要对数据进行排序和分组时。这三种函数都有各自的特点,适用于不同的业务场景。 1. **row_...
在Oracle数据库中,`ROW_NUMBER()`函数是一种窗口函数,主要用于为查询结果中的每一行分配一个唯一的序列号。这一特性使得它在处理分组数据时非常有用,尤其是在需要对数据进行排序并按特定顺序标记每行的情况下。 ...
Oracle数据库中的`row_number() over()`分析函数是一个非常实用的工具,用于为数据集中的每一行分配一个唯一的整数,这个数字基于指定的排序条件。在处理大数据集时,它可以帮助我们进行分页、排名或者在复杂的查询...
ROW_NUMBER () OVER([partition_clause] order_by_clause) dense_rank在做排序时如果遇到列有重复值,则重复值所在行的序列值相同,而其后的序列值依旧递增,rank则是重复值所在行的序列值相同,但其后的序列值从...
在oracle中,有rank,dense_rank,row_number,以及分组排名partition。 说明: rank:排名会出现并列第n名,它之后的会跳过空出的名次,例如:1,2,2,4 dense_rank:排名会出现并列第n名,它之后的名次为n+1,例如:1,2,...
`ROW_NUMBER()`、`RANK()`、`DENSE_RANK()`的区别** - **`ROW_NUMBER()`**: 给每一行分配一个唯一的连续整数,无论是否有并列情况。 - **`RANK()`**: 为每一行分配一个排名,遇到并列情况时跳过某些排名。 - **...
本文将详细介绍Oracle中的`OVER`子句以及几种常用的开窗函数,包括`ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`和`LAG()`等。 #### 二、基本概念 - **`OVER`子句**:`OVER`子句用于指定分析函数的作用范围,它可以...
在Oracle数据库中,`RANK()`函数是一种窗口函数,它被用于在一组数据中为每一行分配一个唯一的排名。此函数特别适用于需要基于特定条件对数据进行排序并为每个记录分配一个名次的情况。在本篇文章中,我们将深入探讨...
OVER函数通常与窗口函数(如RANK(), DENSE_RANK(), ROW_NUMBER(), SUM(), AVG()等)一起使用。其基本语法形式如下: ```sql <window_function> OVER ( [window_spec] ) ``` 其中`<window_function>`代表具体的窗口...
它可以与 `RANK()`, `ROW_NUMBER()`, `DENSE_RANK()` 等函数结合使用,以在特定的行集上执行计算。 `PARTITION BY` 子句则是在每个分区内独立执行操作。它将数据集划分为多个逻辑部分,每个部分有自己的排名或计算...
2. 排序函数 (RANK, DENSE_RANK, ROW_NUMBER) 这些函数用于在特定分组或全表中为行分配唯一的序号。 - RANK():如果两行在同一组中的值相同,它们将被赋予相同的排名,然后跳过下一个排名。 - DENSE_RANK():与RANK...
包含Oracle常用的高级函数,比如取前N名,每个分组的前N名等。 详细介绍Oracle分析函数(OVER、Rank、Dense_rank、row_number、Top/Bottom N、First/Last、NTile) ,窗口函数,报表函数
Oracle数据库中的分析函数是SQL查询中的强大...总的来说,理解并熟练运用RANK()、ROW_NUMBER()和LAG()等分析函数,能帮助数据库管理员和开发人员更好地处理和分析Oracle数据库中的数据,提高数据处理的准确性和效率。
3. **ROW_NUMBER()**:为每个分组内的行提供连续的行号。 4. **LEAD()** 和 **LAG()**:向前或向后查看相邻行的值。 5. **AVG() OVER()**、**SUM() OVER()** 和其他聚合函数:在窗口范围内计算平均值、总和等。 6. *...
2. **DENSE_RANK()**:与RANK()不同,DENSE_RANK()在遇到排名相等的情况时不会在名次中留下空位,这意味着即使有多个数据点并列,下一项仍将紧接在并列名次之后。 3. **CUME_DIST()**:这个函数返回特定值相对于一...
根据提供的文件信息,我们可以深入探讨Oracle分析函数的相关知识点,特别是`SUM()`函数配合`OVER`子句的不同用法,以及`RANK()`, `DENSE_RANK()`, 和 `ROW_NUMBER()` 这三个窗口函数的应用场景。 ### Oracle分析...
在PL/SQL中,可以使用`RANK()`、`DENSE_RANK()`和`ROW_NUMBER()`等函数来实现这一目标。 1. `RANK()` 函数:此函数为每个分组中的行提供唯一的排名。如果有多个行具有相同的值,它们将被分配相同的排名,并且后续的...
本次介绍的是几个常用的Oracle统计函数:row_number()、rank()和dense_rank()。 首先,row_number()函数会为查询结果集中的每一行分配一个唯一的连续整数序列号。这个数字是根据ORDER BY子句中定义的顺序进行排序的...