最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何利用SQL嵌套查询在不使用LIMIT的情况下进行分页?
时间:2026-06-30 09:41:03 编辑:袖梨 来源:一聚教程网
不使用 LIMIT 也能分页,需借助行号变量、TOP 嵌套或窗口函数;MySQL 变量法需同语句初始化且依赖 ORDER BY,高并发易错;SQL Server/Access 用 TOP 子查询依赖排序字段索引;通用方案是窗口函数 ROW_NUMBER() 嵌套过滤,业务条件须置于内层。
不使用 LIMIT 也能分页,但必须换思路:靠行号变量、TOP 嵌套或窗口函数兜底。直接删掉 LIMIT 还想用原逻辑,大概率查出错乱或重复数据。
MySQL 用变量模拟行号分页(仅限低并发小数据)
本质是手动编号再过滤,@rownum 在子查询里累加,外层用 WHERE 截取范围。它不依赖 LIMIT,但有严重限制:
- 必须显式
ORDER BY,否则行号顺序不可控 -
@rownum初始化必须在同一条语句内完成,分开执行(如先SET再SELECT)会失效 - 高并发下变量可能被多个连接覆盖,结果错乱
- MySQL 8.0+ 推荐改用
ROW_NUMBER()窗口函数,更可靠
示例:
SELECT * FROM (<br> SELECT @rownum := @rownum + 1 AS rn, t.*<br> FROM orders t,<br> (SELECT @rownum := 0) r<br> ORDER BY created_at DESC<br>) tmp<br>WHERE rn BETWEEN 21 AND 30;
SQL Server / Access 用 TOP + 子查询实现分页
这是 LIMIT 缺失时最主流的替代方案,核心是“先取前 N 条 ID,再反向筛选”。Access 必须这么写,SQL Server 在 2012 前也常用:
- 第一页:直接
SELECT TOP 10 *加ORDER BY - 后续页:用子查询找出上一页最大/最小排序字段值(比如
id),再WHERE id > xxx范围扫描 - 必须确保排序字段有索引,否则子查询
ORDER BY ... TOP N会全表扫 - Access 不支持
OFFSET,且TOP不能和ORDER BY分开写——SELECT TOP 10 * FROM t ORDER BY id才有效,SELECT TOP 10 * FROM (SELECT * FROM t ORDER BY id)会报错
示例(SQL Server 第二页,每页 10 条):
SELECT TOP 10 *<br>FROM orders<br>WHERE id > (<br> SELECT MAX(id)<br> FROM (<br> SELECT TOP 10 id<br> FROM orders<br> ORDER BY id<br> ) t<br>)<br>ORDER BY id;
所有数据库通用:窗口函数 + 拆层绕过 LIMIT 限制
MySQL 8.0+、PostgreSQL、SQL Server 都支持 ROW_NUMBER(),但注意:不能和 LIMIT 同级共存。必须把带窗口的查询包进子查询,再在外层截取:
- 错误写法:
SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn FROM t LIMIT 10→ MySQL 直接报错 “Window function is not allowed in this context” - 正确写法:窗口计算放内层,
LIMIT放外层;如果真要彻底不用LIMIT,就用WHERE rn BETWEEN x AND y - 业务条件(如
WHERE status = 'shipped')必须写在窗口查询的最内层,否则行号基于全表生成,分页就偏了
示例(纯窗口分页,无 LIMIT):
SELECT * FROM (<br> SELECT *, ROW_NUMBER() OVER (ORDER BY created_at DESC) AS rn<br> FROM orders<br> WHERE status = 'shipped'<br>) t<br>WHERE t.rn BETWEEN 21 AND 30;
真正难的不是写出语法正确的嵌套,而是保证排序字段稳定、索引生效、内外过滤条件完全一致。少一个 WHERE,多一层无意义包装,分页就可能漏数据或重复。