关于Oracle分页写法的思考

背景说明: 

表来源于Oracle 11g内置的hr.employees表。

变量为page(第几页)、size(每页记录数) , 我们都知道查询条件的判断逻辑很简单, 就是rownum >= (page-1)*size并且rownum < page*size,
为什么一个是小于等于, 一个是大于, 因为oracle的rownum是从1开始, 与mysql的limit是零基的不一样。

这里为了直观, 暂且定为每页10条记录, 查看第4页, 即查看第41~50条的记录。

需求:
1) 查看所有列

# 正确写法:
SELECT * FROM ( SELECT rownum rn, e1.* FROM employees e1 WHERE rownum < 50 ) e2 WHERE e2.rn >= 40 ;
# 错误写法: 
SELECT * FROM employees WHERE rownum BETWEEN 40 AND 50;
SELECT * FROM employees WHERE rownum <= 50 AND rownum > 40 ;
SELECT * FROM ( SELECT rownum, * FROM employees WHERE rownum < 50 ) WHERE rownum >= 40;
SELECT e.* FROM ( SELECT rownum rn, * FROM employees WHERE rn <50 ) e WHERE e.rn >=40;...

说明: 错误写法可以五花八门, 主要都是因为对rownum以及SQL语句执行顺序不理解导致。

rownum是从1开始递增, 逐行判断, 符合条件就加入结果集, 有结果集才开始递增。如果一上来就对rownum做了大于1的判断, 就查不到符合条件的结果, 而且要注意BETWEEN是包含边界的。

所以oracle中的分页必须用到子查询, 而且要注意外查询和内查询的rownum必须是同一个rownum, 确保正确的引用。

如果执行不成功, 建议先单独排查一下子查询(内查询)是否写对。


2) 查看指定列(员工号, 姓, 工资)

一般公司都很忌讳SELECT * 的写法, 因为数据库引擎先要去做全表扫描拿到字段名, 所以即使是查所有字段, 也是建议一个个罗列出来。
而且这里查询指定列, 还避免了rownum和*混淆而报错, 比如SELECT rownum, * FROM employees WHERE rownum < 50; 就会报缺失表达式错误。

#正确写法: (这里为了让句子更直观, 就不为字段起别名了)
SELECT employee_id, first_name, salary 
    FROM ( SELECT employee_id, first_name, salary, rownum rn FROM employees WHERE rownum < 50 ) e 
    WHERE e.rn > =40;

怎么样, 是不是比SELECT * 清爽多了。

相关推荐