为了方便大家学习和测试,所有的例子都是在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 s
Oracle数据库的查询中,`OVER (PARTITION BY ..)` 是一种窗口函数的使用方式,它允许我们在分组数据集上执行计算,而不仅仅局限于整个数据集。这种功能在处理复杂的数据分析任务时非常有用,例如计算排名、差异、移动平均等。
我们来看`RANK()`和`DENSE_RANK()`函数。这两种函数都用于对数据进行排名,但它们处理并列的情况有所不同。
1. `RANK() OVER (PARTITION BY ... ORDER BY ...)`: 当在每个分区(由`PARTITION BY`定义)内按照指定的`ORDER BY`字段排序时,`RANK()`会为每个记录分配一个唯一的排名。如果有并列的情况,即多个记录具有相同的排序值,`RANK()`会给它们分配相同的排名,并且接下来的排名会跳过这些数值。比如,如果有两个记录排名为1,那么下一个记录的排名将会是3。
2. `DENSE_RANK() OVER (PARTITION BY ... ORDER BY ...)`: 类似于`RANK()`,`DENSE_RANK()`也会对分区内的记录进行排名,但它不会跳过并列后的排名。如果有并列的记录,它们会获得相同的排名,接下来的记录将获得紧接着的排名。所以,如果有两个记录排名为1,下一个记录的排名仍然是2。
在描述中的例子中,为了找到每个部门工资最高的雇员,我们可以使用`RANK()`或`DENSE_RANK()`配合`PARTITION BY`和`ORDER BY`来实现。这比传统的子查询方法更加简洁和高效。
接下来,我们讨论`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) AS diff_min_sal,
NVL(MAX(e.sal) OVER (PARTITION BY e.deptno) - e.sal, 0) AS diff_max_sal
FROM
scott.emp e;
```
在这个查询中,`MIN(e.sal) OVER (PARTITION BY e.deptno)` 和 `MAX(e.sal) OVER (PARTITION BY e.deptno)` 分别计算了每个部门的最低和最高工资。`NVL` 函数用于处理工资为最小值或最大值的雇员,确保差额始终为非负值。
通过熟练掌握`OVER (PARTITION BY ..)`的用法,我们可以编写出更高效、更灵活的SQL查询,以满足各种复杂的业务需求。对于数据分析和报表生成,窗口函数是Oracle数据库中不可或缺的工具。
Partition by range 是在数据库中对数据进行分区的一种方式,其中按照数据范围将数据分配到不同的分区中。例如,可以按照日期范围将数据分配到每个月的分区中。这样可以提高数据库的性能和可管理性。