rownum是结果集伪列,结果集第一行就是1,第二行就是2
如果ORDER BY与ROWNUM出现在同一个查询语句中的时候,已经排好的ROWNUM可能会被打乱(因为最后执行的ORDER BY)。
CSDN有博客讲,如果ORDER BY的字段是PK的话,会先ORDER BY然后再对查询到的结果集排ROWNUM,如果不是PK或唯一KEY的话,会先排ROWNUM再ORDER BY,但在ORACLE 12.2中实测并不是这样的,例如下面的例子(ID主键):
SELECT ROWNUM,A.* FROM WLPLAT.EMPLOYEE A WHERE ROWNUM < 11 ORDER BY ID;SELECT ROWNUM,A.* FROM WLPLAT.EMPLOYEE A WHERE ROWNUM < 11 ORDER BY NAME;
其结果分别是:
| ROWNUM | ID | NAME |
|---|---|---|
| 5 | 1 | NAME1 |
| 1 | 2 | NAME2 |
| 6 | 3 | NAME3 |
| 10 | 4 | NAME4 |
| 2 | 8 | NAME8 |
| 3 | 10 | NAME10 |
| …. | …. | …. |
| ROWNUM | ID | NAME |
|---|---|---|
| 5 | 1 | NAME1 |
| 3 | 10 | NAME10 |
| 4 | 11 | NAME11 |
| 9 | 13 | NAME13 |
| 1 | 2 | NAME2 |
| 4 | 3 | NAME3 |
| …. | …. | …. |
可以看到ORDER BY总是最后执行的,查看EXPLAIN PLAN也是如此:
那到底PAGING、ROWNUM、ORDER BY怎么结合使用呢?
1:在9(是几忘了)之后版本可以使用ROW_NUMBER函数
SELECT A.*FROM (SELECT A.*, ROW_NUMBER() over (ORDER BY REC_ID) RW FROM WLPLAT.T_MM_STORAGE_DETAIL A) AWHERE RW BETWEEN 200 AND 299;
ROW_NUMBER需要整表排序,所以消耗也大,耗时也略长
12c中非常方便高效的取TOP N ROW的方法
SELECT A.*FROM WLPLAT.T_MM_STORAGE_DETAIL AORDER BY REC_IDFETCH FIRST 100 ROW ONLY;
2:还是使用ROWNUM(三层查询)
SELECT *FROM (SELECT A.*, ROWNUM RWFROM (SELECT A.*FROM WLPLAT.T_MM_STORAGE_DETAIL AORDER BY REC_ID) A WHERE ROWNUM <= 299) AWHERE A.RW > 199;
很明显多加一层避免ORDER BY 影响了 ROWNUM
参考文档:https://docs.oracle.com/cd/E11882_01/server.112/e41084/pseudocolumns009.htm#SQLRF00255
