SQL Server 分页查询 ROW_NUMBER () OFFSET...FETCH游标(Cursor) 数据插入
·
一、分页查询的核心概念
- 定义:将大量数据按 “每页固定条数” 拆分,分批次展示(比如每页显示 10 条,第 1 页显示 1-10 条,第 2 页显示 11-20 条)。
- 用处:避免一次性加载海量数据,提升查询性能和页面加载速度。
- 关键参数:
@CurrentPage:当前要查询的页码(如 “第 2 页”)。@PageSize:每页显示的记录条数(如 “每页 3 条”)。
二、方式 1:ROW_NUMBER () 分页(SQL Server 2012 版本以下适用)
1. 语法定义
ROW_NUMBER() 是一个窗口函数,用于给查询结果的每一行分配一个连续的 “行编号”,结合子查询筛选行编号范围实现分页。
-- 步骤1:定义分页参数
DECLARE @CurrentPage INT; -- 当前页码
DECLARE @PageSize INT; -- 每页条数
-- 步骤2:参数赋值
SET @CurrentPage = 1; -- 示例:查询第1页
SET @PageSize = 3; -- 示例:每页显示3条
-- 步骤3:分页查询(核心)
SELECT * FROM (
-- 子查询:给每一行分配行编号RowId
SELECT
ROW_NUMBER() OVER(ORDER BY 排序列 [ASC/DESC]) AS RowId, -- 按指定列排序后生成行编号
* -- 要查询的列(或指定列名)
FROM 表名
) AS 子查询别名
-- 筛选行编号范围:(当前页-1)*每页条数 +1 ≤ RowId ≤ 当前页*每页条数
WHERE RowId BETWEEN (@CurrentPage - 1) * @PageSize + 1 AND @CurrentPage * @PageSize;
2. 关键语法解释
ROW_NUMBER() OVER(ORDER BY 排序列):ROW_NUMBER():生成连续的行编号(从 1 开始)。OVER(ORDER BY 排序列):指定 “按哪一列排序” 后再分配行编号(必须指定排序,否则行编号无意义)。
- 行编号范围公式:
- 起始 RowId =
(@CurrentPage - 1) * @PageSize + 1(如第 1 页:(1-1)*3+1=1)。 - 结束 RowId =
@CurrentPage * @PageSize(如第 1 页:1*3=3)。
- 起始 RowId =
-- 定义参数
DECLARE @CurrentPage INT;
DECLARE @PageSize INT;
-- 赋值:查询第1页,每页3条
SET @CurrentPage = 1;
SET @PageSize = 3;
-- 分页查询(按Age排序)
SELECT * FROM (
SELECT
ROW_NUMBER() OVER(ORDER BY Age) AS RowId, -- 按Age升序生成行编号
*
FROM Students
) AS S
WHERE RowId BETWEEN (@CurrentPage - 1) * @PageSize + 1 AND @CurrentPage * @PageSize;
- 结果:返回 Students 表中按 Age 排序后的前 3 条数据(第 1 页)。
三、方式 2:OFFSET...FETCH 分页(SQL Server 2012 版本及以上适用)
1. 语法定义
OFFSET...FETCH 是 SQL Server 2012 新增的简化分页语法,直接指定 “跳过的行数” 和 “获取的行数”,写法更简洁。
-- 步骤1:定义分页参数
DECLARE @CurrentPage INT; -- 当前页码
DECLARE @PageSize INT; -- 每页条数
-- 步骤2:参数赋值
SET @CurrentPage = 1; -- 示例:查询第1页
SET @PageSize = 3; -- 示例:每页显示3条
-- 步骤3:分页查询(核心)
SELECT * -- 要查询的列(或指定列名)
FROM 表名
ORDER BY 排序列 [ASC/DESC] -- 必须指定排序
OFFSET (@CurrentPage - 1) * @PageSize ROWS -- 跳过“(当前页-1)*每页条数”行
FETCH NEXT @PageSize ROWS ONLY; -- 获取接下来的“每页条数”行
2. 关键语法解释
OFFSET X ROWS:表示 “跳过前 X 行数据”(X =(@CurrentPage - 1) * @PageSize,如第 1 页:(1-1)*3=0,即不跳过)。FETCH NEXT Y ROWS ONLY:表示 “获取接下来的 Y 行数据”(Y =@PageSize,如每页 3 条)。- 必须配合 ORDER BY:否则 SQL Server 会报错(分页需要明确的排序规则)。
-- 定义参数
DECLARE @CurrentPage INT;
DECLARE @PageSize INT;
-- 赋值:查询第1页,每页3条
SET @CurrentPage = 1;
SET @PageSize = 3;
-- 分页查询(按StudentId排序)
SELECT *
FROM Students
ORDER BY StudentId -- 按StudentId升序排序
OFFSET (@CurrentPage - 1) * @PageSize ROWS -- 跳过0行
FETCH NEXT @PageSize ROWS ONLY; -- 获取3行
- 结果:返回 Students 表中按 StudentId 排序后的前 3 条数据(第 1 页)。
四、两种分页方式对比
| 特性 | ROW_NUMBER () 分页 | OFFSET...FETCH 分页 |
|---|---|---|
| 适用版本 | SQL Server 2005 及以上 | SQL Server 2012 及以上 |
| 语法复杂度 | 较复杂(需要子查询) | 简洁(直接写在主查询) |
| 排序要求 | 必须在 OVER () 中指定 ORDER BY | 必须在主查询中指定 ORDER BY |
| 性能 | 数据量大时略逊于 OFFSET...FETCH | 性能更优(SQL Server 优化过) |
| 适用场景 | 低版本 SQL Server | 高版本 SQL Server(推荐) |
一、游标(Cursor)
1. 定义
游标是 SQL Server 中用于逐行处理查询结果集的数据库对象,它可以将结果集拆分为单行数据,通过 “定位” 和 “读取” 操作逐行处理数据(类似程序中的 “循环遍历”)。
2. 用处
- 当需要逐行处理数据(而非批量处理)时使用(比如逐行读取数据并插入到临时表)。
- 适用于复杂的行级逻辑(批量操作无法实现的场景)。
3. 游标语法(完整流程)
游标使用分为 5 个步骤:定义 → 打开 → 遍历 → 关闭 → 释放。
-- 步骤1:定义游标
DECLARE 游标名称 CURSOR FOR
查询语句; -- 游标要遍历的结果集(如SELECT语句)
-- 步骤2:打开游标(初始化结果集)
OPEN 游标名称;
-- 步骤3:遍历游标(逐行处理数据)
-- 3.1 声明变量存储每行数据
DECLARE @变量1 数据类型, @变量2 数据类型;
-- 3.2 读取游标第一行数据到变量
FETCH NEXT FROM 游标名称 INTO @变量1, @变量2;
-- 3.3 循环遍历(@@FETCH_STATUS=0表示读取成功)
WHILE @@FETCH_STATUS = 0
BEGIN
-- 行级处理逻辑(如插入、更新等)
操作语句;
-- 读取下一行数据
FETCH NEXT FROM 游标名称 INTO @变量1, @变量2;
END;
-- 步骤4:关闭游标(释放结果集资源)
CLOSE 游标名称;
-- 步骤5:释放游标(彻底删除游标对象)
DEALLOCATE 游标名称;
4. 关键语法解释
DECLARE 游标名称 CURSOR FOR 查询语句:定义游标并关联要遍历的结果集。OPEN 游标名称:初始化游标,加载结果集到内存。FETCH NEXT FROM 游标名称 INTO @变量:读取游标当前行的数据到变量,并将游标 “移动到下一行”。@@FETCH_STATUS:系统内置变量,返回游标读取状态:0:读取成功。-1:读取失败(已到结果集末尾)。-2:读取的行不存在。
CLOSE 游标名称:关闭游标,释放结果集资源(但游标对象仍存在)。DEALLOCATE 游标名称:彻底删除游标对象,释放所有资源。
(游标遍历数据插入临时表)
-- 1. 先创建临时表(存储游标遍历的结果)
CREATE TABLE #TempTable (
Score INT,
ScoreCount INT
);
-- 2. 定义游标:关联“按Score分组统计”的结果集
DECLARE Score_cursor CURSOR FOR
SELECT Score, COUNT(Score) AS ScoreCount
FROM ScoreList
GROUP BY Score;
-- 3. 打开游标
OPEN Score_cursor;
-- 4. 声明变量存储每行数据
DECLARE @Score INT, @ScoreCount INT;
-- 5. 读取第一行数据
FETCH NEXT FROM Score_cursor INTO @Score, @ScoreCount;
-- 6. 循环遍历游标
WHILE @@FETCH_STATUS = 0
BEGIN
-- 将当前行数据插入临时表
INSERT INTO #TempTable(Score, ScoreCount)
VALUES (@Score, @ScoreCount);
-- 读取下一行数据
FETCH NEXT FROM Score_cursor INTO @Score, @ScoreCount;
END;
-- 7. 关闭游标
CLOSE Score_cursor;
-- 8. 释放游标
DEALLOCATE Score_cursor;
-- 9. 查看临时表数据
SELECT * FROM #TempTable;
二、INSERT INTO 数据插入(从其他表读取数据)
1. 定义
INSERT INTO... SELECT 是 SQL Server 中批量插入数据的语法,直接从一个表(或查询结果)读取数据并插入到目标表中(无需逐行处理)。
2. 用处
- 批量将一个表的数据(或查询结果)插入到另一个表,效率远高于游标逐行插入。
3. 语法
INSERT INTO 目标表(列1, 列2,...)
SELECT 列1, 列2,... -- 从源表读取的列(需与目标表列匹配)
FROM 源表
[WHERE 条件]; -- 可选:筛选要插入的数据
(从 ScoreList 插入数据到临时表)
-- 1. 创建临时表
CREATE TABLE #TempTable (
Score INT,
ScoreCount INT
);
-- 2. 批量插入:从ScoreList读取“Score在90-100之间”的分组数据
INSERT INTO #TempTable(Score, ScoreCount)
SELECT Score, COUNT(Score) AS ScoreCount
FROM ScoreList
WHERE Score > 90 AND Score <= 100 -- 筛选条件
GROUP BY Score;
-- 3. 查看临时表数据
SELECT * FROM #TempTable;
游标 vs INSERT INTO 批量插入对比
| 特性 | 游标(逐行插入) | INSERT INTO... SELECT(批量插入) |
|---|---|---|
| 操作方式 | 逐行读取、逐行插入 | 批量读取、批量插入 |
| 效率 | 低(频繁 IO 操作) | 高(一次 IO 操作) |
| 适用场景 | 复杂行级逻辑(逐行处理) | 简单批量数据迁移 |
| 代码复杂度 | 高(需 5 步流程) | 低(一行语句) |
更多推荐


所有评论(0)