如何调整分页逻辑从视图获取指定数量唯一Ticket_Id的全量数据?
问题描述
我有一个返回Ticket_Id和Price两列的视图,每个工单最多对应2个不同的Price值。同时我有一个存储过程,通过以下分页参数返回视图数据:
@page : 表示页码 @pageSize : 表示每页记录数
当用户请求100条唯一工单数据时,我需要返回最多200行数据(每个工单最多2条价格记录)。但当前使用的分页逻辑:
OFFSET ', @pageSize,' * (',@page,' - 1) ROWS FETCH NEXT ', @pageSize,' ROWS ONLY
只会返回包含重复Ticket_Id的100行数据,无法满足需求。请问如何修改分页参数来获取全部对应行?
示例
视图返回结果如下:
| ticket_id | price |
|---|---|
| ticket1 | 10 |
| ticket1 | 12 |
| ticket2 | 11 |
| ticket2 | 13 |
| ticket3 | 12 |
| ticket3 | 14 |
当传入参数@page = 1, @PageSize = 3时,需要返回全部6行数据(对应3个唯一工单的所有价格记录)。
视图定义
(因存储过程无法直接访问tickets表,故使用视图)
select tck.ticket_id, tck.cost as 'price' --,RANK() OVER(ORDER BY tck.ticket_id) 'Rank' from tickets tck with (NOLOCK)
存储过程定义
ALTER PROCEDURE [dbo].[p_trans_history_srch] @page int = 1, -- optional @pageSize int = 20 -- optional AS BEGIN DECLARE @finalsqlstmt nvarchar(max) DECLARE @pageString nvarchar(max) DECLARE @pageCount nvarchar(max) = '' DECLARE @viewName nvarchar(max) SET @pageString = CONCAT(' OFFSET ', @pageSize,' * (',@page,' - 1) ROWS FETCH NEXT ', @pageSize,' ROWS ONLY') SET @finalsqlstmt = CONCAT('SELECT * FROM ', dbo.f_get_dbname(), @viewName, 'WHERE ',@search ,' AND created_date BETWEEN ''', @startDate, ''' AND ''', @endDate, ''' ORDER BY created_date DESC', @pageString) SET @pageCount = CONCAT('SELECT COUNT(DISTINCT ticket_id) FROM ', dbo.f_get_dbname(), @viewName, 'WHERE ', @search, ' AND created_date BETWEEN ''', @startDate, ''' AND ''', @endDate, '''') EXEC (@finalsqlstmt) EXEC (@pageCount) END
注意事项
我曾尝试使用RANK() OVER(ORDER BY ticket_id) 'Rank'并基于排名返回数据,但因表数据量过大,查询性能骤降。
解决方案
核心思路是先对唯一工单进行分页,再关联视图获取所有对应价格记录,既保证分页逻辑按工单数量计算,又避免全表排序导致的性能问题。
修改存储过程中的@finalsqlstmt部分,替换为以下逻辑:
SET @finalsqlstmt = CONCAT( 'WITH PaginatedTickets AS (', 'SELECT DISTINCT ticket_id ', 'FROM ', dbo.f_get_dbname(), @viewName, ' ', 'WHERE ', @search, ' AND created_date BETWEEN ''', @startDate, ''' AND ''', @endDate, ''' ', 'ORDER BY created_date DESC ', 'OFFSET ', @pageSize, ' * (', @page, ' - 1) ROWS ', 'FETCH NEXT ', @pageSize, ' ROWS ONLY ', ')', 'SELECT v.* ', 'FROM ', dbo.f_get_dbname(), @viewName, ' v ', 'INNER JOIN PaginatedTickets pt ON v.ticket_id = pt.ticket_id ', 'ORDER BY v.created_date DESC, v.ticket_id' );
逻辑说明
- 分页筛选唯一工单:通过CTE
PaginatedTickets先提取符合条件的唯一ticket_id,并按@page和@pageSize分页,这一步仅针对工单数量处理,数据量小,性能不受影响。 - 关联视图获取全量数据:将分页后的工单ID与原视图关联,取出每个工单对应的所有价格记录,最终返回行数为分页工单数量×最多2行,完全匹配需求。
- 保持排序一致性:最终结果按
created_date DESC和ticket_id排序,与原逻辑输出顺序一致。
额外注意
- 原存储过程中的
@pageCount逻辑无需修改,它原本就是统计唯一工单数量,与新的分页逻辑完全匹配。 - 若
ticket_id和created_date存在联合索引,可进一步提升CTE部分的查询性能。
内容的提问来源于stack exchange,提问作者sandesh b n
相关产品推荐
相关产品推荐

