oracle row_number用法
### Oracle Row_Number 函数详解 #### 一、Row_Number 基础概念 在Oracle数据库中,`ROW_NUMBER()`函数是一种窗口函数,主要用于为查询结果中的每一行分配一个唯一的序列号。这一特性使得它在处理分组数据时非常有用,尤其是在需要对数据进行排序并按特定顺序标记每行的情况下。 #### 二、Row_Number 基本语法 `ROW_NUMBER()`函数的基本语法如下: ```sql ROW_NUMBER() OVER (PARTITION BY <column_list> ORDER BY <order_by_expression>) ``` - **PARTITION BY**:用于指定按照哪些列进行分组。 - **ORDER BY**:用于指定如何对分组内的行进行排序。 #### 三、Row_Number 实例分析 1. **基础用法** ```sql SELECT ROW_NUMBER() OVER (ORDER BY SALE / CNT DESC) AS SORT, SALE / CNT FROM ( SELECT -60 AS SALE, 3 AS CNT FROM DUAL UNION SELECT 24 AS SALE, 6 AS CNT FROM DUAL UNION SELECT 50 AS SALE, 5 AS CNT FROM DUAL UNION SELECT -20 AS SALE, 2 AS CNT FROM DUAL UNION SELECT 40 AS SALE, 8 AS CNT FROM DUAL ); ``` 这段代码根据`SALE / CNT`的值降序排列,并为每行分配一个递增的序列号。执行结果如下: | SORT | SALE / CNT | |------|------------| | 1 | 10 | | 2 | 5 | | 3 | 4 | | 4 | -10 | | 5 | -20 | 2. **PARTITION BY 的使用** 当使用`PARTITION BY`时,会基于指定的列将结果集分成不同的组,并为每个组内的行单独分配序列号。例如: ```sql SELECT ENAME, SAL, ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS SAL_ORDER FROM SCOTT.EMP; ``` 上述查询结果将按部门分组,并按薪资降序排列。结果如下: | ENAME | SAL | SAL_ORDER | |-------|-------|-----------| | KING | 5000 | 1 | | CLARK | 2450 | 2 | | MILLER| 1300 | 3 | | SCOTT | 3000 | 1 | | FORD | 3000 | 2 | | JONES | 2975 | 3 | | ADAMS | 1100 | 4 | | SMITH | 800 | 5 | | BLAKE | 2850 | 1 | | ALLEN | 1600 | 2 | | TURNER| 1500 | 3 | | WARD | 1250 | 4 | | MARTIN| 1250 | 5 | | JAMES | 950 | 6 | 3. **过滤特定行** 可以通过结合`WHERE`子句来选择特定的行。例如,仅选择部门内薪资排名前二的员工: ```sql SELECT DEPTNO, ENAME, SAL FROM ( SELECT DEPTNO, ENAME, SAL, ROW_NUMBER() OVER (PARTITION BY DEPTNO ORDER BY SAL DESC) AS SAL_ORDER FROM SCOTT.EMP ) WHERE SAL_ORDER < 2; ``` 结果如下: | DEPTNO | ENAME | SAL | |--------|-------|-------| | 10 | KING | 5000 | | 20 | SCOTT | 3000 | | 30 | BLAKE | 2850 | 4. **与 Rank 和 Dense_Rank 的比较** `ROW_NUMBER()`可以与`RANK()`和`DENSE_RANK()`进行比较。这些函数都可以用来给数据排序并分配等级,但是它们在处理并列的情况时有所不同: - **Rank**:如果两个或多个行具有相同的排序值,则这些行都将获得相同的排名,而下一个排名将跳过。 - **Dense_Rank**:如果两个或多个行具有相同的排序值,则这些行都将获得相同的排名,但下一个排名不会跳过。 - **Row_Number**:为每一行分配一个唯一的连续整数值。 例如,使用`RANK()`: ```sql SELECT DEPTNO, SAL, RANK() OVER (PARTITION BY DEPTNO ORDER BY SAL) AS RANK_ORDER FROM SCOTT.EMP ORDER BY DEPTNO; ``` 结果如下: | DEPTNO | SAL | RANK_ORDER | |--------|-------|------------| | 10 | 1300 | 1 | | 10 | 2450 | 2 | | 10 | 5000 | 3 | | 20 | 800 | 1 | | 20 | 1100 | 2 | | 20 | 2975 | 3 | | 20 | 3000 | 4 | | 20 | 3000 | 5 | | 30 | 950 | 1 | | 30 | 1250 | 2 | | 30 | 1250 | 3 | | 30 | 1500 | 4 | | 30 | 1600 | 5 | | 30 | 2850 | 6 | 5. **使用 Lag 函数** `LAG()`函数用于访问当前行前面的行的值。例如,获取同一部门内前一个员工的名字: ```sql SELECT DEPTNO, ENAME, SAL, LAG(ENAME, 1, NULL) OVER (PARTITION BY DEPTNO ORDER BY ENAME) AS LAG_ENAME FROM SCOTT.EMP ORDER BY DEPTNO; ``` 结果如下: | DEPTNO | ENAME | SAL | LAG_ENAME | |--------|-------|-------|-----------| | 10 | CLARK | 2450 | NULL | | 10 | KING | 5000 | CLARK | | 10 | MILLER| 1300 | KING | | 20 | ADAMS | 1100 | NULL | | 20 | FORD | 3000 | ADAMS | | 20 | JONES | 2975 | FORD | | ... | ... | ... | ... | #### 四、Row_Number 的高级应用 除了以上基础用法外,`ROW_NUMBER()`还可以与其他窗口函数组合使用,实现更复杂的数据分析需求。例如,结合`LAG()`和`LEAD()`函数可以实现数据的前后对比;与`RANK()`和`DENSE_RANK()`结合则可以进一步细化排序逻辑,为数据分析提供更多的可能性。 #### 五、总结 `ROW_NUMBER()`函数是Oracle数据库中一个非常强大的工具,特别是在需要对数据进行分组和排序时。通过掌握其基本用法以及与其他窗口函数的结合使用,可以在数据处理和分析方面发挥重要作用。无论是简单的排序还是复杂的分组分析,`ROW_NUMBER()`都能够提供有效的解决方案。
与rownum的区别在于:使用rownum进行排序的时候是先对结果集加入伪列rownum然后再进行排序,而此函数在包含排序从句后是先排序再计算行号码.
row_number()和rownum差不多,功能更强一点(可以在各个分组内从1开时排序).
rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内).
dense_rank()l是连续排序,有两个第二名时仍然跟着第三名。相比之下row_number是没有重复值的 .
lag(arg1,arg2,arg3):
arg1是从其他行返回的表达式
arg2是希望检索的当前行分区的偏移量。是一个正的偏移量,时一个往回检索以前的行的数目。
arg3是在arg2表示的数目超出了分组的范围时返回的值。
简单介绍如下:
早扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下:
第一步:从根节点开始;
第二步:访问该节点;
第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步;
第四步:若该节点为根节点,则访问完毕,否则执行第五步;
第五步:返回到该节点的父节点,并执行第三步骤。
总之:扫描整个树结构的过程也即是中序遍历树的过程。
看几个SQL语句:
语句一:
from (
select -60 as sale,3 as cnt from dual union
select 24 as sale,6 as cnt from dual union
select 50 as sale,5 as cnt from dual union
select -20 as sale,2 as cnt from dual union
select 40 as sale,8 as cnt from dual);
执行结果:
SORT SALE/CNT
---------- ----------
1 10
2 5
3 4
4 -10
5 -20
语句二:查询员工的工资,按部门排序
select ename,sal,row_number() over (partition by deptno order by sal desc) as sal_order from scott.emp;
执行结果:
ENAME SAL SAL_ORDER
-------------------- ---------- ----------
KING 5000 1
CLARK 2450 2
剩余5页未读,继续阅读
- nyf5552012-05-16只是进行了一些简单的用法,有待进一步研究
- 粉丝: 0
- 资源: 2
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助