概述
今天主要总结一下Oracle、MySQL、sqlserver、PG数据库在分页上的一些实现方案及对比,仅供参考。
一、Oracle分页实现
oracle的分页一共有三种方式,但在Oracle中实现分页的方法主要是用ROWNUM关键字和用ROWID关键字两种。
Rownum 和 Rowid是Oracle数据库所特有的,通过他们可以查询到指定行数范围内的数据记录。
1、根据rowid来分
Oracle使用rowid数据类型存储行地址,rowid是物理存在的,实际存在的一个列,是一种数据类型。 基于64为编码的18个字符来唯一标识的一条记录的物理位置的一个ID。而唯一标识出对应的存储的物理位置, 类似hashcode值。
rowid可以分成两种,分别适于不同的对象:
- 1)Physical rowids:存储ordinary table,clustered table,table partition and subpartition,indexe,index partition and subpartition
- 2)Logical rowids : 存储IOT的行地址
另一种rowid类型叫universal rowed(UROWID),支持上述physical rowid和logical rowed,并且支持非oracle table, 即支持所有类型的rowid, 但COMPATIBLE必须在8.1或以上.
每个表在oracle内部都有一个ROWID伪列,它在所有sql中无法显示,不占存储空间; 它用于从表中查询行的地址或者在where中进行参照,rowid伪列不存储在数据库中,它不是数据库数据,这是从database及table的逻辑结构来说的,事实上,在物理结构上,每行由一个或多个row pieces组成,每个row piece的头部包含了这个piece的address,即rowid.从这个意义上来说,rowid还是占了磁盘空间的。
我们在创建表时,可以为列指定为rowid数据类型,但oracle并不保证列中的数据是合法的rowid值,必须由应用程序来保证, 另外,类型为rowid的列需要6 bytes存储数据
一般实现分页的过程如下:
- 1)获取数据物理地址:SELECT ROWID RID, tablenumber FROM table_name ORDER BY tablenumber DESC
- 2)取得最大页数:SELECT ROWNUM RN, RID FROM (SELECT ROWID RID, tablenumber FROM table_name ORDER BY tablenumber DESC) WHERE ROWNUM <= xx
- 3)取得最小页数:SELECT RID FROM(SELECT ROWNUM RN, RID FROM (SELECT ROWID RID, tablenumber FROM table_name ORDER BY tablenumber DESC) WHERE ROWNUM <= xx)
- 4)因为取得的页数都是物理地址,再根据物理地址,查询出具体数据
相关sql如下:
--currentPage:当前页数
--pageSize:每页显示几条
SELECT *
FROM table_name
WHERE ROWID IN
(SELECT RID
FROM (SELECT ROWNUM RN, RID
FROM (SELECT ROWID RID, tablenumber
FROM table_name
ORDER BY tablenumber DESC)
WHERE ROWNUM <= ((currentPage - 1) * pageSize + pageSize))
WHERE RN > ((currentPage - 1) * pageSize))
ORDER BY tablenumber DESC;
2、按分析函数 ROW_NUMBER() OVER()来分
语法格式:row_number() over(partition by 分组列 order by 排序列 desc)
oracle中的ROW_NUMBER() OVER(partition by col1 order by col2) 表示根据col1分组,在分组内部根据col2排序,而此函数计算的值就表示每组内部
排序后的顺序编号(组内是连续且唯一的)
一般实现分页的过程如下:
--currentPage:当前页数
--pageSize:每页显示几条
SELECT *
FROM (SELECT T.*, ROW_NUMBER() OVER(ORDER BY tablenumber DESC) RK FROM t T)
WHERE RK <= ((currentPage - 1) * pageSize + pageSize)
AND RK > ((currentPage - 1) * pageSize);
3、根据rownum 来分
rownum是伪列,是在获取查询结果集后再加上去的 (获取一条记录加一个rownum)。对符合条件的结果添加一个从1开始的序列号
对于rownum来说它是oracle系统顺序分配为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推,这个伪字段可以用于限制查询返回的总行数,且rownum不能以任何表的名称作为前缀。
一般实现分页的过程如下:
--currentPage:当前页数
--pageSize:每页显示几条
SELECT *
FROM (SELECT T.*, ROWNUM RN
FROM (SELECT * FROM t ORDER BY tablenumber DESC) T
WHERE ROWNUM <= ((currentPage - 1) * pageSize + pageSize))
WHERE RN > ((currentPage - 1) * pageSize);
4、存储过程实现
这个存储过程主要是让大家看看分页的实现过程,可忽略
--1、开发一个包,在该包中,定义类型test_cursor,是个游标
create or replace package testpackage as
type test_cursor is ref cursor;
end testpackage;
--2、开始编写分页的过程
create or replace procedure fenye(tableName in varchar2, --表名
pageSize in number, --一页显示记录数
pageNow in number, --当前页
myrows out number, --总记录数
myPageCount out number, --总页数
p_cursor out testpackage.test_cursor --返回的记录集
) is
--定义部分
--定义sql语句 字符串
v_sql varchar2(1000);
--定义两个整数
v_begin number := (pageNow - 1) * pageSize + 1;
v_end number := pageNow * pageSize;
begin
--执行部份
v_sql := 'select * from (select t1.*,rownum rn from (select * from ' ||
tableName || ') t1 where rownum<=' || v_end || ') where rn>=' ||
v_begin;
--把游标和sql关联
open p_cursor for v_sql;
--计算myrows和myPageCount
--组织一个sql
v_sql := 'select count(*) from ' || tableName;
--执行sql,并把返回的值赋给myrows;
execute immediate v_sql
into myrows;
--计算myPageCount
if mod(myrows, PageSize) = 0 then
myPageCount := myrows / PageSize;
else
myPageCount := myrows / PageSize + 1;
end if;
--关闭游标
close p_cursor;
end;
5、实例演示
5.1、环境准备
create table t(EMPNO NUMBER(4) not null,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE DATE,
SAL NUMBER(7,2),
COMM NUMBER(7,2),
DEPTNO NUMBER(2));
alter table t add constraint PK_EMP primary key (EMPNO) using index;
INSERT INTO t VALUES ('7369', 'SMITH', 'CLERK', '7902', TO_DATE('1980-12-17 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '800', NULL, '20');
INSERT INTO t VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', TO_DATE('1981-02-20 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1600', '300', '30');
INSERT INTO t VALUES ('7521', 'WARD', 'SALESMAN', '7698', TO_DATE('1981-02-22 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1250', '500', '30');
INSERT INTO t VALUES ('7566', 'JONES', 'MANAGER', '7839', TO_DATE('1981-04-02 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '2975', NULL, '20');
INSERT INTO t VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', TO_DATE('1981-09-28 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1250', '1400', '30');
INSERT INTO t VALUES ('7698', 'BLAKE', 'MANAGER', '7839', TO_DATE('1981-05-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '2850', NULL, '30');
INSERT INTO t VALUES ('7782', 'CLARK', 'MANAGER', '7839', TO_DATE('1981-06-09 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '2450', NULL, '10');
INSERT INTO t VALUES ('7788', 'SCOTT', 'ANALYST', '7566', TO_DATE('1987-04-19 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '3000', NULL, '20');
INSERT INTO t VALUES ('7839', 'KING', 'PRESIDENT', NULL, TO_DATE('1981-11-17 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '5000', NULL, '10');
INSERT INTO t VALUES ('7844', 'TURNER', 'SALESMAN', '7698', TO_DATE('1981-09-08 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1500', '0', '30');
INSERT INTO t VALUES ('7876', 'ADAMS', 'CLERK', '7788', TO_DATE('1987-05-23 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1100', NULL, '20');
INSERT INTO t VALUES ('7900', 'JAMES', 'CLERK', '7698', TO_DATE('1981-12-03 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '950', NULL, '30');
INSERT INTO t VALUES ('7902', 'FORD', 'ANALYST', '7566', TO_DATE('1981-12-03 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '3000', NULL, '20');
INSERT INTO t VALUES ('7934', 'MILLER', 'CLERK', '7782', TO_DATE('1982-01-23 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), '1300', NULL, '10');
commit;

5.2、根据rowid查询
--查询当前第一页,并显示5行数据(currentPage=1,pagesize=5)
SELECT *
FROM t
WHERE ROWID IN
(SELECT RID
FROM (SELECT ROWNUM RN, RID
FROM (SELECT ROWID RID, EMPNO FROM t ORDER BY EMPNO DESC)
WHERE ROWNUM <= ( (1-1) * 5 + 5 )) --每页显示几条
WHERE RN > ((1-1) * 5) ) --当前页数
ORDER BY EMPNO DESC;
--查询当前第二页,并显示6行数据(currentPage=2,pagesize=6)
SELECT *
FROM t
WHERE ROWID IN
(SELECT RID
FROM (SELECT ROWNUM RN, RID
FROM (SELECT ROWID RID, EMPNO FROM t ORDER BY EMPNO DESC)
WHERE ROWNUM <= ( (2-1) * 6 + 6)) --每页显示几条
WHERE RN > ((2-1) * 6) ) --当前页数
ORDER BY EMPNO DESC;


5.3、根据分页函数查询
--查询当前第一页,并显示6行数据(currentPage=1,pagesize=6)
SELECT *
FROM (SELECT T.*, ROW_NUMBER() OVER(ORDER BY tablenumber DESC) RK FROM t T)
WHERE RK <= ((1 - 1) * 5 + 5) --每页显示几条
AND RK > ((1 - 1) * 5); --当前页数

5.4、根据分页函数查询
--查询当前第二页,并显示4行数据(currentPage=2,pagesize=4)
SELECT *
FROM (SELECT T.*, ROWNUM RN
FROM (SELECT * FROM t ORDER BY empno DESC) T
WHERE ROWNUM <= ((2 - 1) * 4 + 4))
WHERE RN > ((2 - 1) * 4);

二、mysql分页实现
MySQL中实现分页查询:在数据量较小的情况下可使用limit查询来实现分页查询,在数据量大的情况下使用建立主键或唯一索引来实现,另外可通过order by对其排序。
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants, with these exceptions:
- Within prepared statements, LIMIT parameters can be specified using ? placeholder markers.
- Within stored programs, LIMIT parameters can be specified using integer-valued routine parameters or local variables.
1、limit分页实现
先看一下limit语法
SELECT * FROM TABLE
[ORDER BY {col_name | expr | position}
[ASC | DESC], ... [WITH ROLLUP]]
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
LIMIT子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT接受一个或两个数字参数。参数必须是一个整数常量。
如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1)。
1.1、传统实现方式
一般情况下,客户端通过传递 pageNo(页码)、pageSize(每页条数)两个参数去分页查询数据库中的数据,在数据量较小(元组百/千级)时使用 MySQL自带的 limit 来解决这个问题
--pageNo:页码
--pagesize:每页显示的条数
select * from table limit (pageNo-1)*pageSize,pageSize;
1.2、建立主键或者唯一索引(高效)
在数据量较小的时候简单的使用 limit 进行数据分页在性能上面不会有明显的缓慢,但是数据量达到了 万级到百万级 sql语句的性能将会影响数据的返回。这时需要利用主键或者唯一索引进行数据分页;
--pageNo:页码
--pagesize:每页显示的条数
--假设主键或者唯一索引为 t_id
select * from table where t_id > (pageNo-1)*pageSize limit pageSize;
1.3、基于数据再排序
当需要返回的信息为顺序或者倒序时,对上面的语句基于数据再排序。order by ASC/DESC 顺序或倒序 默认为顺序
select * from table where t_id > (pageNo-1)*pageSize order by t_id limit pageSize;
2、查询显示行号(实现类似Oracle数据库的ROWNUM())
Oracle中有专门的rownum()显示行号的函数,而MySQL没有专门的显示行号函数,但可以通过用@rownum自定义变量显示行号。
一般实现过程如下:
SELECT
(@rownum := @rownum + 1) AS rownum,
t.*
FROM
table t,
(SELECT @rownum := 0) AS rn
3、实例演示
3.1、环境准备
CREATE TABLE t (
EMPNO BIGINT ( 4 ) NOT NULL,
ENAME VARCHAR ( 10 ),
JOB VARCHAR ( 9 ),
MGR BIGINT ( 4 ),
HIREDATE date,
SAL BIGINT ( 10 ),
COMM BIGINT ( 10 ),
DEPTNO BIGINT ( 2 ),
PRIMARY KEY ( `EMPNO` )
) ENGINE = INNODB;
INSERT INTO t VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', NULL, '20');
INSERT INTO t VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO t VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO t VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', NULL, '20');
INSERT INTO t VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO t VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', NULL, '30');
INSERT INTO t VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', NULL, '10');
INSERT INTO t VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', NULL, '20');
INSERT INTO t VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17', '5000', NULL, '10');
INSERT INTO t VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500', '0', '30');
INSERT INTO t VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', NULL, '20');
INSERT INTO t VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', NULL, '30');
INSERT INTO t VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', NULL, '20');
INSERT INTO t VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', NULL, '10');
commit;

3.2、limit分页
--查询第一页,每页显示5条数据
select * from t order by empno desc limit (1-1)*5,5;
--查询第二页,每页显示4条数据
select * from t order by empno desc limit (2-1)*4,4;


3.3、查询显示行号
--查询第二页,每页显示4条数据,并在第一列加上行号
select (@rownum := @rownum + 1) AS rownum,t.* from t,
(SELECT @rownum := 0) AS rn
order by t.empno desc
limit 4,4;

ps:还可以考虑存储过程实现…
三、mssql分页实现
SQL server的分页与MySQL的分页的不同,mysql的分页直接是用limit (pageIndex-1),pageSize就可以完成,但是SQL server 并没有limit关键字,只有类似limit的top关键字。所以分页起来比较麻烦。
1、三重循环
先取前20页,然后倒序,取倒序后前10条记录,这样就能得到分页所需要的数据,不过顺序反了,之后可以将再倒序回来,也可以不再排序了,直接交给前端排序。还有一种方法是先查询出前10条记录,然后用not in排除了这10条,再查询。
一般实现过程如下:
-- 设置执行时间开始,用来查看性能的
set statistics time on ;
-- 分页查询
select *
from (select top pageSize *
from (select top(pageIndex * pageSize) *
from t
order by tablenumber asc) -- 其中里面这层,必须指定按照升序排序,省略的话,查询出的结果是错误的。
as temp
order by tablenumber desc) temp_2
order by tablenumber asc
2、利用max(主键)
先top前11条行记录,然后利用max(id)得到最大的id,之后再重新再这个表查询前10条,不过要加上条件,where id>max(id)。
一般实现过程如下:
set statistics time on;
-- 分页查询
select top pageSize *
from table
where tablenumber >=
(select max(tablenumber)
from (select top((pageIndex - 1) * pageSize + 1) tablenumber
from table
order by tablenumber asc) temp_max_ids)
order by tablenumber;
3、利用row_number关键字
直接利用row_number() over(order by id)函数计算出行数,选定相应行数返回即可,不过该关键字只有在SQL server 2005版本以上才有。
set statistics time on;
-- 分页查询
select top pageSize *
from (select row_number() over(order by tablenumber asc) as rownumber,*
from table) temp_row
where rownumber > ((pageIndex - 1) * pageSize);
4、offset /fetch next(2012版本及以上才有)
offset A rows ,将前A条记录舍去,fetch next B rows only ,向后在读取B条数据。
set statistics time on;
-- 分页查询
select * from table
order by tablenumber
offset((@pageIndex - 1) * @pageSize) rows
fetch next @pageSize rows only;
5、存储过程实现
写分页的时候,直接调用这个分页存储过程
create procedure paging_procedure
( @pageIndex int, -- 第几页
@pageSize int -- 每页包含的记录数
)
as
begin
select top (select @pageSize) * -- 这里注意一下,不能直接把变量放在这里,要用select
from (select row_number() over(order by tablenumber) as rownumber,*
from table) temp_row
where rownumber>(@pageIndex-1)*@pageSize;
end
-- 到时候直接调用就可以了,执行如下的语句进行调用分页的存储过程
exec paging_procedure @pageIndex=2,@pageSize=10;
6、实例演示
6.1、环境准备
CREATE TABLE [dbo].[t] (
[EMPNO] decimal(12) NULL,
[ENAME] nvarchar(10) COLLATE Chinese_PRC_CI_AS NOT NULL,
[JOB] nvarchar(10) COLLATE Chinese_PRC_CI_AS NOT NULL,
[MGR] decimal(12) NULL,
[HIREDATE] datetime,
[SAL] decimal(12) NULL,
[COMM] decimal(12) NULL,
[DEPTNO] decimal(12) NULL
)
GO
ALTER TABLE [dbo].[t] SET (LOCK_ESCALATION = TABLE)
GO
INSERT INTO [dbo].[t] VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17 00:00:00', '800', NULL, '20');
INSERT INTO [dbo].[t] VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20 00:00:00', '1600', '300', '30');
INSERT INTO [dbo].[t] VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22 00:00:00', '1250', '500', '30');
INSERT INTO [dbo].[t] VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02 00:00:00', '2975', NULL, '20');
INSERT INTO [dbo].[t] VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28 00:00:00', '1250', '1400', '30');
INSERT INTO [dbo].[t] VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01 00:00:00', '2850', NULL, '30');
INSERT INTO [dbo].[t] VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09 00:00:00', '2450', NULL, '10');
INSERT INTO [dbo].[t] VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19 00:00:00', '3000', NULL, '20');
INSERT INTO [dbo].[t] VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17 00:00:00', '5000', NULL, '10');
INSERT INTO [dbo].[t] VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08 00:00:00', '1500', '0', '30');
INSERT INTO [dbo].[t] VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23 00:00:00', '1100', NULL, '20');
INSERT INTO [dbo].[t] VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03 00:00:00', '950', NULL, '30');
INSERT INTO [dbo].[t] VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03 00:00:00', '3000', NULL, '20');
INSERT INTO [dbo].[t] VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23 00:00:00', '1300', NULL, '10');
GO

6.2、利用max实现
set statistics time on;
-- 分页查询
select top 5 *
from t
where empno >=
(select max(empno)
from (select top((1 - 1) * 5 + 2) empno
from t
order by empno asc) temp_max_ids)
order by empno desc;

6.3、利用row_number实现(推荐)
set statistics time on;
-- 分页查询
select top 6 *
from (select row_number() over(order by empno desc) as rownumber,*
from t) temp_row
where rownumber > ((1 - 1) * 6);

四、pg数据库分页实现
pg数据库分页语法如下:
select * from table limit A offset B;
参数:
- A就是需要多少行;
- B就是查询的起点位置。
基于上面语法介绍PG的5种分页实现方案,如下:
1、分页方案1
select *
from table
where 自增列 in (select 自增列
from 表
ORDER BY 自增列 desc limit (select count(*) - (页码 * 显示数)
from table))
ORDER BY 自增列 asc limit 显示数;
示例:
select * from read_sight_order_log where id in ( select id from read_sight_order_log ORDER BY id desc limit (select count(*) - (0*10) from read_sight_order_log)) ORDER BY id asc limit 10
2、分页方案2
select *
from table
where 自增列 not in
(select 自增列 from table ORDER BY 自增列 asc limit 页码 * 显示数)
ORDER BY 自增列 asc limit 显示数
示例:
select * from read_sight_order_log where id not in (select id from read_sight_order_log ORDER BY id asc limit 0 * 10) ORDER BY id asc limit 10
3、分页方案3
select * from table order by 排序列 asc LIMIT 显示数 offset (页码-1) * 显示数
示例:
select * from read_sight_order_log order by id asc LIMIT 10 offset 0*10
4、分页方案4
select *
from table
where 自增列 BETWEEN 页码 * 显示数 and (1 + 页码) * 显示数
示例:
select * from read_sight_order_log where id BETWEEN 0* 10 and (1+0 )*10
5、分页方案5
select *
from (select *,row_number() over(order by 列 asc) as rownumber from table) t
where t.rownumber > 页码*显示数
and t.rownumber <= (1+页码)*显示数
示例:
select * from (select *,row_number() over(order by id asc) as idx from read_sight_order_log)t where t.idx>0 * 10 and t.idx<= (1+0)*10
6、实例演示
6.1、环境准备
$ psql -h xx.107 -p 5432 FSL-VIS postgres
\dn --list schemas
set search_path to 'fslvis_schema';
\dt --list tables
CREATE TABLE t(
EMPNO INT PRIMARY KEY NOT NULL,
ENAME CHAR(10) NOT NULL,
JOB CHAR(10) NOT NULL,
MGR INT,
HIREDATE date,
SAL INT,
COMM INT,
DEPTNO INT
);
INSERT INTO t VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', NULL, '20');
INSERT INTO t VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO t VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO t VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', NULL, '20');
INSERT INTO t VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO t VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', NULL, '30');
INSERT INTO t VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', NULL, '10');
INSERT INTO t VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', NULL, '20');
INSERT INTO t VALUES ('7839', 'KING', 'PRESIDENT', NULL, '1981-11-17', '5000', NULL, '10');
INSERT INTO t VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500', '0', '30');
INSERT INTO t VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', NULL, '20');
INSERT INTO t VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', NULL, '30');
INSERT INTO t VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', NULL, '20');
INSERT INTO t VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', NULL, '10');

6.2、分页实现
select * from t
where empno in (select empno from t ORDER BY empno desc limit (select count(*) - (1 * 5) from t))
ORDER BY empno desc limit 5;
--或者以下
select * from t order by empno desc LIMIT 5 offset 0 * 5;

