上一篇
分页存储过程 多条件
- 行业动态
- 2025-05-03
- 3071
分页存储过程通过动态拼接SQL实现多条件筛选,利用OFFSET-FETCH分页,参数化处理条件防注入,结合ORDER BY排序保证数据连续性
分页存储过程与多条件查询的实现与优化
在数据库开发中,分页查询和多条件筛选是常见需求,通过存储过程实现分页与多条件组合查询,既能提升性能,又能增强代码复用性,以下从原理、实现到优化进行全面解析。
分页查询的核心原理
分页的本质是通过限制返回数据的范围,常见两种方式:
OFFSET + FETCH(适用于SQL Server、PostgreSQL等)
- 语法:
SELECT FROM Table ORDER BY [col] OFFSET @StartRow ROWS FETCH NEXT @PageSize ROWS ONLY
- 优点:简单直观,适合小数据量分页。
- 缺点:大数据量时效率低(需扫描前
@StartRow
行)。
- 语法:
ROW_NUMBER() 窗口函数(推荐方式)
- 语法:
SELECT FROM ( SELECT , ROW_NUMBER() OVER (ORDER BY [col]) AS RowNum FROM Table WHERE [conditions] ) AS T WHERE T.RowNum BETWEEN @StartRow AND @EndRow
- 优点:性能更优,适合大数据量分页。
- 缺点:需排序字段,且窗口函数可能增加计算开销。
- 语法:
方法 | 适用场景 | 性能特点 |
---|---|---|
OFFSET+FETCH | 小数据量、简单分页 | 高并发时效率下降 |
ROW_NUMBER() | 大数据量、复杂排序 | 依赖索引,性能稳定 |
多条件查询的动态处理
多条件查询需根据用户输入动态拼接WHERE
条件,常见实现方式:
动态SQL拼接
- 根据传入参数是否为空,动态生成
WHERE
子句。 - 示例(SQL Server):
DECLARE @SQL NVARCHAR(MAX) = 'SELECT FROM Table WHERE 1=1' IF @Condition1 IS NOT NULL SET @SQL += ' AND Col1 = @Condition1' IF @Condition2 IS NOT NULL SET @SQL += ' AND Col2 LIKE ''%''+@Condition2+''%''' EXEC sp_executesql @SQL, N'@Condition1 INT, @Condition2 VARCHAR(50)', @Condition1, @Condition2
- 根据传入参数是否为空,动态生成
可选参数处理
- 存储过程参数允许
NULL
值,通过判断参数是否为空决定是否应用条件。 - 示例:
WHERE (@StartDate IS NULL OR DateCol >= @StartDate) AND (@EndDate IS NULL OR DateCol <= @EndDate)
- 存储过程参数允许
分页与多条件结合的存储过程实现
以下以SQL Server为例,实现支持多条件+分页的通用存储过程:
CREATE PROCEDURE GetPagedData @PageNumber INT, @PageSize INT, -多条件参数 @Condition1 VARCHAR(50) = NULL, @Condition2 DATE = NULL, @SortField VARCHAR(50) = 'ID', -默认排序字段 @SortDirection VARCHAR(10) = 'ASC' -ASC/DESC AS BEGIN DECLARE @StartRow INT = (@PageNumber 1) @PageSize + 1; DECLARE @EndRow INT = @PageNumber @PageSize; -动态构建SQL DECLARE @SQL NVARCHAR(MAX) = 'SELECT FROM ( SELECT , ROW_NUMBER() OVER (ORDER BY ' + QUOTENAME(@SortField) + ' ' + CASE WHEN @SortDirection = 'ASC' THEN ''ASC'' ELSE ''DESC'' END + ') AS RowNum FROM TableName WHERE 1=1' + CASE WHEN @Condition1 IS NOT NULL THEN ' AND Col1 LIKE ''%''+@Condition1+''%''' ELSE '' END + CASE WHEN @Condition2 IS NOT NULL THEN ' AND DateCol = @Condition2' ELSE '' END + ') AS T WHERE T.RowNum BETWEEN @StartRow AND @EndRow'; EXEC sp_executesql @SQL, N'@StartRow INT, @EndRow INT, @Condition1 VARCHAR(50), @Condition2 DATE', @StartRow, @EndRow, @Condition1, @Condition2; END
关键参数与逻辑说明
参数名 | 类型 | 说明 |
---|---|---|
@PageNumber | INT | 当前页码(从1开始) |
@PageSize | INT | 每页数据量 |
@Condition1 | VARCHAR(50) | 模糊匹配条件(如名称/描述) |
@Condition2 | DATE | 精确匹配条件(如日期范围) |
@SortField | VARCHAR(50) | 排序字段(需与表中列名一致) |
@SortDirection | VARCHAR(10) | 排序方向(ASC/DESC) |
逻辑流程:
- 计算分页范围(
@StartRow
到@EndRow
)。 - 根据非空条件动态拼接
WHERE
子句。 - 使用
ROW_NUMBER()
生成行号,最终过滤行号范围。
性能优化建议
索引优化:
- 对排序字段(如
@SortField
)和条件字段(如Col1
、DateCol
)建立索引。 - 避免在
WHERE
条件中对字段使用函数(如LIKE '%value%'
可能导致全表扫描)。
- 对排序字段(如
参数化查询:
- 使用
sp_executesql
而非直接拼接SQL,防止SQL注入并提升执行计划重用率。
- 使用
分页方式选择:
- 大数据量优先使用
ROW_NUMBER()
,小数据量可用OFFSET+FETCH
。
- 大数据量优先使用
FAQs
Q1:如何测试存储过程的分页功能?
A1:可通过插入模拟数据(如使用INSERT INTO TableName VALUES (...)
生成大量记录),然后调用存储过程并逐步调整@PageNumber
和@PageSize
,验证返回结果是否符合预期。
EXEC GetPagedData @PageNumber=1, @PageSize=10, @Condition1='test', @SortField='CreateTime';
Q2:如果传入的条件参数为NULL
,存储过程会如何处理?
A2:存储过程中对每个条件参数均做了NULL
判断。@Condition1
为NULL
时,动态SQL不会拼接AND Col1 LIKE
条件,相当于忽略该筛选规则,其他参数同理,确保