SQL Server笔记 -- 第80章:分页

在各版本 SQL Server 中使用行偏移与分页技术


节80.1:使用 OFFSET FETCH 分页

适用版本 ≥ SQL Server 2012

OFFSET FETCH 子句以更简洁的方式实现分页:跳过 N₁ 行(OFFSET 指定)后返回接下来的 N₂ 行(FETCH 指定)。

sql 复制代码
SELECT *
FROM sys.objects
ORDER BY object_id
OFFSET 40 ROWS
FETCH NEXT 10 ROWS ONLY;

ORDER BY 子句必须存在,以保证确定性顺序。


节80.2:使用内层查询分页

在较早版本的 SQL Server 中,需结合双重排序与 TOP 关键字实现分页:

sql 复制代码
SELECT TOP 10 *
FROM (
    SELECT TOP 50
        object_id,
        name,
        type,
        create_date
    FROM sys.objects
    ORDER BY name ASC
) AS data
ORDER BY name DESC;

内层查询先按 name 升序取前 50 行;外层再按 name 降序取前 10 行,即得到原序列的第 41--50 行。


节80.3:各版本 SQL Server 分页写法

SQL Server 2012/2014

sql 复制代码
DECLARE @RowsPerPage INT = 10,
        @PageNumber INT = 4;

SELECT OrderId, ProductId
FROM OrderDetail
ORDER BY OrderId
OFFSET (@PageNumber - 1) * @RowsPerPage ROWS
FETCH NEXT @RowsPerPage ROWS ONLY;

SQL Server 2005/2008/R2

sql 复制代码
DECLARE @RowsPerPage INT = 10,
        @PageNumber INT = 4;

SELECT OrderId, ProductId
FROM (
    SELECT
        OrderId,
        ProductId,
        ROW_NUMBER() OVER (ORDER BY OrderId) AS RowNum
    FROM OrderDetail
) AS OD
WHERE OD.RowNum BETWEEN ((@PageNumber - 1) * @RowsPerPage) + 1
                    AND @RowsPerPage * @PageNumber;

SQL Server 2000

sql 复制代码
DECLARE @RowsPerPage INT = 10,
        @PageNumber INT = 4;

SELECT OrderId, ProductId
FROM (
    SELECT TOP (@RowsPerPage)
        OrderId, ProductId
    FROM (
        SELECT TOP ((@PageNumber) * @RowsPerPage)
            OrderId, ProductId
        FROM OrderDetail
        ORDER BY OrderId
    ) AS OD
    ORDER BY OrderId DESC
) AS OD2
ORDER BY OrderId ASC;

节80.4:SQL Server 2012/2014 使用 ORDER BY OFFSET 与 FETCH NEXT

获取接下来 10 行:

sql 复制代码
SELECT *
FROM TableName
ORDER BY id
OFFSET 10 ROWS
FETCH NEXT 10 ROWS ONLY;

要点:

  • ORDER BY 必须存在,才能使用 OFFSET 与 FETCH。
  • OFFSET 子句必须与 FETCH 一起出现;不能单独使用 ORDER BY ... FETCH
  • 同一查询中不可将 TOP 与 OFFSET/FETCH 混用。

节80.5:使用 ROW_NUMBER 与公用表表达式实现分页

适用版本 ≥ SQL Server 2008

ROW_NUMBER 函数可为结果集的每一行分配递增序号,结合公用表表达式 (CTE) 与 BETWEEN 运算符,可得到"页"结果:

sql 复制代码
WITH data AS (
    SELECT
        ROW_NUMBER() OVER (ORDER BY name) AS row_id,
        object_id,
        name,
        type,
        create_date
    FROM sys.objects
)
SELECT *
FROM data
WHERE row_id BETWEEN 41 AND 50;

注意:ROW_NUMBER 不能直接用于 WHERE 子句,如:

sql 复制代码
SELECT object_id, name, type, create_date
FROM sys.objects
WHERE ROW_NUMBER() OVER (ORDER BY name) BETWEEN 41 AND 50

执行将报错:

复制代码
消息 4108,级别 15,状态 1,行 6
窗口函数只能出现在 SELECT 或 ORDER BY 子句中。
相关推荐
小光学长20 小时前
基于ssm的膳食健康管理系统e6whl4q7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·开发语言·数据库·学习·ssm
java1234_小锋20 小时前
Java高频面试题:Redis到底支不支持事务啊?
java·redis·面试
无心水20 小时前
【常见错误】2、Java并发编程避坑指南:从加锁失效到死锁,10个案例教你正确使用锁
java·开发语言·python
我爱学习好爱好爱20 小时前
Kubernetes 1.29集群上部署Java网站项目
java·容器·kubernetes
青衫码上行20 小时前
【项目开发日记 | Java架构】第一天
java·开发语言·spring cloud
一个天蝎座 白勺 程序猿20 小时前
KingbaseES融合数据库:一库多能,企业数据管理新思路
数据库·性能优化·kingbasees·金仓数据库
DJ斯特拉20 小时前
自定义jar包导入maven&&注册第三方bean
java·maven·jar
橘颂TA20 小时前
【MySQL】解锁表的 N 种牵手方式:SQL 连接与子查询漫游(复合查询)
数据库·mysql
j_xxx404_21 小时前
力扣困难算法精解:串联所有单词的子串与最小覆盖子串
java·开发语言·c++·算法·leetcode·哈希算法
数据知道21 小时前
MongoDB基于角色的访问控制(RBAC):精细化权限管理的实用方法
数据库·mongodb