下面用查询工资排名21-30的员工信息,举例Oracle分页查询语法
Oracle传统分页查询语法:
SELECT * FROM (SELECT a.*, ROWNUM rn FROM (SELECT *FROM employeeORDER BY salary desc) a WHERE ROWNUM <= 30
)
WHERE rn > 20;
ROWNUM
伪列是Oracle中查询数据后自动赋值的序号字段,从1开始,逐行递增。传统分页方式通过ROWNUM
伪列实现,需要比较复杂的三层查询,下面分析一下为什么需要三层。
Oracle中查询语句各阶段执行顺序
步骤 | 执行阶段 | 说明 |
---|---|---|
1 | FROM / JOIN | 首先从表中读取数据,执行连接等操作。 |
2 | WHERE | 过滤数据(此时还 没有 ROWNUM)。 |
3 | 分配 ROWNUM(特殊阶段) | Oracle 在结果集中给每一行分配 ROWNUM(此时尚未排序)。 |
4 | ROWNUM 条件生效 | 可以用来过滤,比如 ROWNUM <= 10 。注意:不能用 ROWNUM > 10 直接分页,因为 ROWNUM 是先从1开始依次赋值的。 |
5 | GROUP BY | 对数据分组。 |
6 | HAVING | 对分组结果进一步过滤。 |
7 | SELECT | 返回指定的字段。 |
8 | ORDER BY | 最后才排序!这意味着ROWNUM 赋值发生在排序前,不是排好序后再编号。 |
单层查询为什么不行
SELECT employee.*FROM employeeWHERE RUWNUM > 20 AND RUWNUM <= 30ORDER BY salary desc
ROWNUM
伪列是在查询数据之后赋值的,第一条符合过滤条件的记录,ROWNUM
被赋值为1,第二条符合过滤条件的记录ROWNUM
为2…,因为ROWNUM
初始值为1,不满足ROWNUM > 20
条件,导致始终没有满足条件的记录,ROWNUM
无法自增,最终查出0条记录。
二层查询为什么不行
SELECT t.* FROM (SELECT employee.*, RUWNUM RNFROM employeeORDER BY salary desc
) tWHERE t.RN > 20 AND t.RN <= 30
ROWNUM
伪列是在ORDER BY之前执行的,最后虽然能查出结果,但不满足排序规则。
三层查询的作用
- 第一层查询:将数据按指定规则排序。
- 第二层查询:ROWNUM从1开始,所以
ROWNUM <= 30
过滤前30名的记录。 - 第三层查询:
RN > 21
过滤21名及之后记录。
第二层和第三层的过滤条件不能颠倒,要先判断小于,再判断大于。
附录Oracle12c以后支持分页查询语法:
SELECT * FROM employee
ORDER BY salary
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
注意偏移量OFFSET从0开始,上面SQL表示从21名开始向后查询10条记录。