#1 楼
获取结果总数和分页是两个不同的操作。就本例而言,我们假设您要处理的查询是SELECT * FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
在这种情况下,您将使用以下方法确定结果总数:
SELECT COUNT(*) FROM Orders WHERE OrderDate >= '1980-01-01'
......看似效率低下,但在假设所有索引等均已正确设置的情况下,实际上表现不错。
接下来,为了以分页的方式返回实际结果,以下查询将是最有效的:
SELECT *
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY OrderDate ) AS RowNum, *
FROM Orders
WHERE OrderDate >= '1980-01-01'
) AS RowConstrainedResult
WHERE RowNum >= 1
AND RowNum < 20
ORDER BY RowNum
这将返回原始查询的第1-19行。在这里,特别是对于Web应用程序来说,很酷的事情是,除了要返回的行号之外,您不必保留任何状态。
评论
只是要注意ROW_NUMBER()在SQL Server 2000中不存在
–约翰·亨特(John Hunter)
08年12月3日在13:28
这会从内部查询返回所有行,然后根据外部查询进行过滤吗?例如:内部查询返回100,000,外部查询仅返回20。
–SoftwareGeek
2011年6月16日在3:59
@SoftwareGeek:将其视为返回流的子查询(内部查询),然后读取该流,直到满足外部WHERE子句为止。与行相关的方式完全取决于查询,但是优化程序通常在最小化该数目方面做得很好。在这方面,使用SQL Server Management Studio中的图形执行计划查看器(使用查询/包含实际执行计划)非常有帮助。
–mdb
2011年6月16日7:51
好吧,如果您在内部选择中复制了内容(例如当您具有内部联接时),您将如何使用distinct,因为RowNumber不同并且它不起作用
–user217648
2012年8月3日在12:18
Microsoft向SQL 2012添加了一项新功能,该功能使分页类似于MySQL。点击此链接以了解操作方法。这是一篇有趣的文章:dbadiaries.com/…
– Arash
2013年12月20日13:49
#2 楼
最终,Microsoft SQL Server 2012发布了,我真的很喜欢它的简单性,便于分页,您不必使用像此处回答的复杂查询。要获取接下来的10行,只需运行以下查询:
SELECT * FROM TableName ORDER BY id OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
https://docs.microsoft.com/zh-cn/ sql / t-sql / queries /按子句选择事务处理sql#using-offset-and-fetch-to-limit-rows-returned
要考虑的关键点使用它:
ORDER BY
是必须使用OFFSET ... FETCH
子句的。OFFSET
子句对于FETCH
是必需的。您不能使用ORDER BY ...
FETCH
。TOP
不能与OFFSET
和FETCH
在同一查询中组合。表达式。
评论
仍在等待LISTAGG()/ GROUP_CONCAT()。
–培根片
2014年11月10日20:07
@BaconBits有关使用FOR XML的狡猾方法,请参见以下答案:stackoverflow.com/a/273330/429949
–Richard Marskell-Drackir
15年7月22日在15:48
@ RichardMarskell-Drackir FOR XML PATH('')有很多问题。首先,它将XML控制字符替换为XML实体代码。希望您的数据中没有<,>或&!其次,以这种方式使用的FOR XML PATH('')实际上是未记录的语法。您应该指定一个命名列或备用元素名称。在文档中既不做任何事,也不意味着行为不可靠。第三,我们对破损的FOR XML PATH('')语法的接受程度越高,MS实际提供真正需要的LISTAGG()[OVER()]函数的可能性就越小。
–培根片
15年7月22日在16:13
羞愧的性能是如此糟糕mssqlgirl.com/…
–乔恩
2015年9月8日15:29在
@Jon,该链接的博客文章不具有代表性,从某种意义上说,它是基于通过查找id列的值返回页面结果进行比较的。
–诺埃尔·亚伯拉罕(Noel Abrahams)
15年11月13日在11:38
#3 楼
令人难以置信的是,没有其他答案提到在所有SQL Server版本中进行分页的最快方法。对于较大的页码,胶印可能非常慢,如此处基准所示。在SQL中有一种完全不同的,更快的方法来执行分页。如本文中的博客文章所述,这通常称为“搜索方法”或“键集分页”。SELECT TOP 10 first_name, last_name, score, COUNT(*) OVER()
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
“搜索谓词”
@previousScore
和@previousPlayerId
值是上一页中最后一条记录的相应值。这使您可以获取“下一页”页面。如果ORDER BY
的方向是ASC
,则只需改用>
。使用上述方法,如果不先获取前40条记录,就无法立即跳至第4页。但是通常,您还是不想跳得那么远。取而代之的是,您将获得一个更快的查询,该查询可能能够在恒定时间内获取数据,具体取决于您的索引编制。另外,无论基础数据是否发生更改(例如,在第1页上,而在第4页上),您的页面仍保持“稳定”状态。
这是在延迟加载时实现分页的最佳方法例如,Web应用程序中的更多数据。
注意,“搜索方法”也称为键集分页。
COUNT(*) OVER()
窗口功能将帮助您计算“分页之前”的总记录数。如果使用的是SQL Server 2000,则必须对COUNT(*)
进行两个查询。评论
@ user960567:就性能而言,无论您是使用SQL标准OFFSET .. FETCH还是使用先前的ROW_NUMBER()技巧实现偏移量分页,键集分页都将始终优于偏移量分页。
–卢卡斯·埃德(Lukas Eder)
14年4月16日在14:31
我对seek方法有三个问题。 [1]用户无法跳至页面。 [2]它假定使用连续键,即如果某人删除了3行,那么我得到的页面将是7个而不是10个。RowNumber每页给我提供了一致的10个项目。 [3]它不适用于假定页面号和页面大小的现有网格。
–丽贝卡
15年7月29日在9:55
@Junto:键集分页不适用于所有情况。绝对不是数据网格。但这对于诸如Facebook提要页面的无限滚动之类的场景非常理想。不管是否在顶部添加新帖子,在向下滚动时,后续的Feed帖子都将正确添加到底部。完美的用法示例...使用偏移量限制/仅使用数字获取将很难实现。
– Robert Koritnik
2015年7月31日,0:21
我必须同意Junto。此方法完全排除了具有漂亮标准分页ui的客户端“上一个1 2 3(4)5 6下一个”,用户可以在其中前进。根据我的经验,这并不是一个极端的情况。
– AaronHS
15年11月27日在6:10
按键分页文章在这里
– Stphane
17年8月9日在16:30
#4 楼
从SQL Server 2012开始,我们可以使用OFFSET
和FETCH NEXT
子句实现分页。 对于SQL Server,请尝试以下操作:
在SQL Server 2012中,ORDER BY子句中添加了新功能,
用于查询优化集数据,使使用T-SQL编写的任何人以及整个SQL Server中的整个执行计划的数据分页工作变得更容易。
T-下面SQL脚本具有与以前的
示例中使用的逻辑相同的逻辑。
--CREATING A PAGING WITH OFFSET and FETCH clauses IN "SQL SERVER 2012"
DECLARE @PageNumber AS INT, @RowspPage AS INT
SET @PageNumber = 2
SET @RowspPage = 10
SELECT ID_EXAMPLE, NM_EXAMPLE, DT_CREATE
FROM TB_EXAMPLE
ORDER BY ID_EXAMPLE
OFFSET ((@PageNumber - 1) * @RowspPage) ROWS
FETCH NEXT @RowspPage ROWS ONLY;
TechNet:使用SQL Server分页查询
评论
该审判中最准确的答案
–守望者
2月19日11:14
@Vikrant仅当您忽略所有运行低于2012版本的人时
–傻瓜
8月19日8:42
#5 楼
MSDN:ROW_NUMBER(Transact-SQL)返回结果集分区中一行的顺序号,从每个分区中第一行的1开始。
下面的示例按OrderDate的顺序返回编号为50到60的行。
WITH OrderedOrders AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY FirstName DESC) AS RowNumber,
FirstName, LastName, ROUND(SalesYTD,2,1) AS "Sales YTD"
FROM [dbo].[vSalesPerson]
)
SELECT RowNumber,
FirstName, LastName, Sales YTD
FROM OrderedOrders
WHERE RowNumber > 50 AND RowNumber < 60;
RowNumber FirstName LastName SalesYTD
--- ----------- ---------------------- -----------------
1 Linda Mitchell 4251368.54
2 Jae Pak 4116871.22
3 Michael Blythe 3763178.17
4 Jillian Carson 3189418.36
5 Ranjit Varkey Chudukatil 3121616.32
6 José Saraiva 2604540.71
7 Shu Ito 2458535.61
8 Tsvi Reiter 2315185.61
9 Rachel Valdez 1827066.71
10 Tete Mensa-Annan 1576562.19
11 David Campbell 1573012.93
12 Garrett Vargas 1453719.46
13 Lynn Tsoflias 1421810.92
14 Pamela Ansman-Wolfe 1352577.13
#6 楼
在http://www.codeproject.com/KB/aspnet/PagingLarge.aspx上可以很好地概述不同的分页技术。我在SQL Server 2000中经常使用ROWCOUNT方法(也可以与2005和2008一起使用,只需衡量性能(与ROW_NUMBER相比)即可,闪电般快速,但是您需要确保已排序的列具有(大部分)唯一值。评论
有趣的是,该文章没有提到seek方法,该方法能够在恒定时间内执行分页...仍然是一篇不错的文章
–卢卡斯·埃德(Lukas Eder)
13-10-26在17:53
#7 楼
对于SQL Server 2000,您可以使用带有IDENTITY列的表变量模拟ROW_NUMBER():DECLARE @pageNo int -- 1 based
DECLARE @pageSize int
SET @pageNo = 51
SET @pageSize = 20
DECLARE @firstRecord int
DECLARE @lastRecord int
SET @firstRecord = (@pageNo - 1) * @pageSize + 1 -- 1001
SET @lastRecord = @firstRecord + @pageSize - 1 -- 1020
DECLARE @orderedKeys TABLE (
rownum int IDENTITY NOT NULL PRIMARY KEY CLUSTERED,
TableKey int NOT NULL
)
SET ROWCOUNT @lastRecord
INSERT INTO @orderedKeys (TableKey) SELECT ID FROM Orders WHERE OrderDate >= '1980-01-01' ORDER BY OrderDate
SET ROWCOUNT 0
SELECT t.*
FROM Orders t
INNER JOIN @orderedKeys o ON o.TableKey = t.ID
WHERE o.rownum >= @firstRecord
ORDER BY o.rownum
此方法可以扩展到具有多列键的表,它不会招致使用OR的性能开销(跳过索引的使用)。不利的一面是,如果数据集非常大且一个数据集位于最后一页附近,则已用完的临时空间量。在那种情况下,我没有测试游标的性能,但是可能会更好。
请注意,可以针对数据的第一页优化此方法。另外,由于TOP在SQL Server 2000中不接受变量,因此使用了ROWCOUNT。
#8 楼
在sql server 2012中进行分页的最佳方法是在存储过程中使用offset和fetch next。OFFSET关键字-如果我们将offset与order by子句一起使用,则查询将跳过我们在OFFSET中指定的记录数n行。
FETCH NEXT关键字-当我们仅将Fetch Next与order by子句一起使用时,它将返回您要在分页中显示的行数,而没有Offset,则SQL会生成错误。 br />这是下面给出的示例。
create procedure sp_paging
(
@pageno as int,
@records as int
)
as
begin
declare @offsetcount as int
set @offsetcount=(@pageno-1)*@records
select id,bs,variable from salary order by id offset @offsetcount rows fetch Next @records rows only
end
您可以按以下方式执行它。
exec sp_paging 2,3
#9 楼
这些是我在SQL Server端分页查询结果的解决方案。这些方法在SQL Server 2008和2012之间有所不同。
我还添加了按一列过滤和排序的概念。在Gridview中进行分页,筛选和排序时,这非常有效。
在测试之前,您必须创建一个示例表并在该表中插入一些行:(在现实世界中,您必须进行更改where子句考虑了您的表字段,也许您在select的主要部分中有一些联接和子查询)
Create Table VLT
(
ID int IDentity(1,1),
Name nvarchar(50),
Tel Varchar(20)
)
GO
Insert INTO VLT
VALUES
('NAME' + Convert(varchar(10),@@identity),'FAMIL' + Convert(varchar(10),@@identity))
GO 500000
在所有这些示例中,我想查询每行200行页,而我正在获取页号1200的行。
在SQL Server 2008中,可以使用CTE概念。因此,我为SQL Server 2008+编写了两种查询类型– SQL Server 2008+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
) AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
GO
第二种解决方案SQL Server 2008+中具有CTE的服务器
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
ROW_NUMBER()
OVER( ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN VLT.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN VLT.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN VLT.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN VLT.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN VLT.Tel END ASC
) AS RowNum
,*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
WHERE Data.RowNum > @PageSize * (@PageNumber - 1)
AND Data.RowNum <= @PageSize * @PageNumber
ORDER BY Data.RowNum
-SQL Server 2012+
DECLARE @PageNumber Int = 1200
DECLARE @PageSize INT = 200
DECLARE @SortByField int = 1 --The field used for sort by
DECLARE @SortOrder nvarchar(255) = 'ASC' --ASC or DESC
DECLARE @FilterType nvarchar(255) = 'None' --The filter type, as defined on the client side (None/Contain/NotContain/Match/NotMatch/True/False/)
DECLARE @FilterValue nvarchar(255) = '' --The value the user gave for the filter
DECLARE @FilterColumn int = 1 --The column to wich the filter is applied, represents the column number like when we send the information.
;WITH
Data_CTE
AS
(
SELECT
*
FROM VLT
WHERE
( -- We apply the filter logic here
CASE
WHEN @FilterType = 'None' THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 1
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.ID NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 1
AND VLT.ID = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 1
AND VLT.ID <> @FilterValue THEN 1
-- Name column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 2
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Name NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 2
AND VLT.Name = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 2
AND VLT.Name <> @FilterValue THEN 1
-- Tel column filter
WHEN @FilterType = 'Contain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'NotContain' AND @FilterColumn = 3
AND ( -- In this case, when the filter value is empty, we want to show everything.
VLT.Tel NOT LIKE '%' + @FilterValue + '%'
OR
@FilterValue = ''
) THEN 1
WHEN @FilterType = 'Match' AND @FilterColumn = 3
AND VLT.Tel = @FilterValue THEN 1
WHEN @FilterType = 'NotMatch' AND @FilterColumn = 3
AND VLT.Tel <> @FilterValue THEN 1
END
) = 1
)
SELECT
Data.ID,
Data.Name,
Data.Tel
FROM Data_CTE AS Data
ORDER BY
CASE WHEN @SortByField = 1 AND @SortOrder = 'ASC'
THEN Data.ID END ASC,
CASE WHEN @SortByField = 1 AND @SortOrder = 'DESC'
THEN Data.ID END DESC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'ASC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 2 AND @SortOrder = 'DESC'
THEN Data.Name END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'ASC'
THEN Data.Tel END ASC,
CASE WHEN @SortByField = 3 AND @SortOrder = 'DESC'
THEN Data.Tel END ASC
OFFSET @PageSize * (@PageNumber - 1) ROWS FETCH NEXT @PageSize ROWS ONLY;
#10 楼
尝试这种方法:SELECT TOP @offset a.*
FROM (select top @limit b.*, COUNT(*) OVER() totalrows
from TABLENAME b order by id asc) a
ORDER BY id desc;
#11 楼
明智地使用案例,以下内容似乎易于使用且速度很快。只需设置页码即可。use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6;
with result as(
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
)
select SalesOrderDetailID, SalesOrderID, ProductID from result
WHERE result.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
也无需CTE
use AdventureWorks
DECLARE @RowsPerPage INT = 10, @PageNumber INT = 6
SELECT SalesOrderDetailID, SalesOrderID, ProductID
FROM (
SELECT SalesOrderDetailID, SalesOrderID, ProductID,
ROW_NUMBER() OVER (ORDER BY SalesOrderDetailID) AS RowNum
FROM Sales.SalesOrderDetail
where 1=1
) AS SOD
WHERE SOD.RowNum BETWEEN ((@PageNumber-1)*@RowsPerPage)+1
AND @RowsPerPage*(@PageNumber)
评论
先生,在1 = 1处做什么?
– Errol Paleracio
19年12月2日,下午1:57
#12 楼
从2012年起,我们可以使用OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
#13 楼
好吧,我在SQL 2000数据库中使用了以下示例查询,它也适用于SQL 2005。通过使用多列,它为您提供的功能可以动态排序。我告诉你...功能强大:)
ALTER PROCEDURE [dbo].[RE_ListingReports_SelectSummary]
@CompanyID int,
@pageNumber int,
@pageSize int,
@sort varchar(200)
AS
DECLARE @sql nvarchar(4000)
DECLARE @strPageSize nvarchar(20)
DECLARE @strSkippedRows nvarchar(20)
DECLARE @strFields nvarchar(4000)
DECLARE @strFilter nvarchar(4000)
DECLARE @sortBy nvarchar(4000)
DECLARE @strFrom nvarchar(4000)
DECLARE @strID nvarchar(100)
If(@pageNumber < 0)
SET @pageNumber = 1
SET @strPageSize = CAST(@pageSize AS varchar(20))
SET @strSkippedRows = CAST(((@pageNumber - 1) * @pageSize) AS varchar(20))-- For example if pageNumber is 5 pageSize is 10, then SkippedRows = 40.
SET @strID = 'ListingDbID'
SET @strFields = 'ListingDbID,
ListingID,
[ExtraRoom]
'
SET @strFrom = ' vwListingSummary '
SET @strFilter = ' WHERE
CompanyID = ' + CAST(@CompanyID As varchar(20))
End
SET @sortBy = ''
if(len(ltrim(rtrim(@sort))) > 0)
SET @sortBy = ' Order By ' + @sort
-- Total Rows Count
SET @sql = 'SELECT Count(' + @strID + ') FROM ' + @strFROM + @strFilter
EXEC sp_executesql @sql
--// This technique is used in a Single Table pagination
SET @sql = 'SELECT ' + @strFields + ' FROM ' + @strFROM +
' WHERE ' + @strID + ' IN ' +
' (SELECT TOP ' + @strPageSize + ' ' + @strID + ' FROM ' + @strFROM + @strFilter +
' AND ' + @strID + ' NOT IN ' + '
(SELECT TOP ' + @strSkippedRows + ' ' + @strID + ' FROM ' + @strFROM + @strFilter + @SortBy + ') '
+ @SortBy + ') ' + @SortBy
Print @sql
EXEC sp_executesql @sql
最好的部分是sp_executesql缓存以后的调用,前提是您传递相同的参数,即生成相同的sql文字。
#14 楼
CREATE view vw_sppb_part_listsource as
select row_number() over (partition by sppb_part.init_id order by sppb_part.sppb_part_id asc ) as idx, * from (
select
part.SPPB_PART_ID
, 0 as is_rev
, part.part_number
, part.init_id
from t_sppb_init_part part
left join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
where prev.SPPB_PART_ID is null
union
select
part.SPPB_PART_ID
, 1 as is_rev
, prev.part_number
, part.init_id
from t_sppb_init_part part
inner join t_sppb_init_partrev prev on ( part.SPPB_PART_ID = prev.SPPB_PART_ID )
) sppb_part
当涉及到不同的init_id
时,将重新启动idx
#15 楼
对于ROW_NUMBER
技术,如果没有要使用的排序列,则可以按以下方式使用CURRENT_TIMESTAMP
:SELECT TOP 20
col1,
col2,
col3,
col4
FROM (
SELECT
tbl.col1 AS col1
,tbl.col2 AS col2
,tbl.col3 AS col3
,tbl.col4 AS col4
,ROW_NUMBER() OVER (
ORDER BY CURRENT_TIMESTAMP
) AS sort_row
FROM dbo.MyTable tbl
) AS query
WHERE query.sort_row > 10
ORDER BY query.sort_row
这对我来说搜索效果很好表的大小甚至可以达到700,000。
这将获取记录11到30。
评论
好的做法是,使用分页,您应该尝试按结果集中唯一的一组列进行排序,因为不应认为顺序是有保证的。
– Arin Taylor
16 Sep 25 '21:55
这将获取记录11到30。
–阿达兰(Ardalan Shahgholi)
16-10-5在15:07
#16 楼
create PROCEDURE SP_Company_List (@pagesize int = -1 ,@pageindex int= 0 ) > AS BEGIN SET NOCOUNT ON;
select Id , NameEn from Company ORDER by Id ASC
OFFSET (@pageindex-1 )* @pagesize ROWS FETCH NEXt @pagesize ROWS ONLY END GO
DECLARE @return_value int
EXEC @return_value = [dbo].[SP_Company_List] @pagesize = 1 , > @pageindex = 2
SELECT 'Return Value' = @return_value
GO
#17 楼
该位使您能够使用SQL Server和更新版本的MySQL进行分页,并携带每一行的总行数。使用您的pimary键计算唯一行数。
WITH T AS
(
SELECT TABLE_ID, ROW_NUMBER() OVER (ORDER BY TABLE_ID) AS RN
, (SELECT COUNT(TABLE_ID) FROM TABLE) AS TOTAL
FROM TABLE (NOLOCK)
)
SELECT T2.FIELD1, T2.FIELD2, T2.FIELD3, T.TOTAL
FROM TABLE T2 (NOLOCK)
INNER JOIN T ON T2.TABLE_ID=T.TABLE_ID
WHERE T.RN >= 100
AND T.RN < 200
评论
您能否留下任何解释您的代码功能的注释?
–道格F
19 Mar 27 '19 at 17:01
#18 楼
这与2012年的旧SO问题重复:实现分页的有效方法
FROM [TableX]
ORDER BY [FieldX]
OFFSET 500行
仅次于100行
这里将详细讨论此主题,并提供其他替代方法。
#19 楼
您没有指定语言,也没有指定使用哪个驱动程序。因此,我正在抽象地描述它。创建一个可滚动的结果集/数据集。这就要求表上的主键
跳到末尾
请求行数
跳到页面的开头
滚动到行的末尾。页面
评论
我一直想知道为什么他们不仅仅支持在TOP中指定偏移量(例如MySQL / Posgresql支持LIMIT / OFFSET)。例如,它们可能仅具有语法“ SELECT TOP x,y ....”,其中x =行数,y =起始偏移量。它也将向后兼容。嘿,我也是... sql 2005分页实现,真的很尴尬...
@gregmac-Sql Server 2012现在确实具有限制/偏移。
公认的解决方案并未显示出最佳方法(性能方面)。将任何数据备份到大型数据集上吗?
@ O.O:一个很好的基准可以在这里找到:4guysfromrolla.com/webtech/042606-1.shtml。但是,seek方法将胜过任何基于偏移量的分页。