有一种简单的方法可以从任何表中获得前N行:
SELECT TOP 10 * FROM MyTable ORDER BY MyColumn
是否有任何有效的方法可以从第N行开始查询M行
例如,
Id Value
1 a
2 b
3 c
4 d
5 e
6 f
并像这样查询
SELECT [3,2] * FROM MyTable ORDER BY MyColumn /* hypothetical syntax */
从3d行开始查询2行,即返回3d和第4行。
答案 0 :(得分:88)
更新如果您使用的是SQL 2012,则会添加新语法以使其变得非常简单。见Implement paging (skip / take) functionality with this query
我想最优雅的是使用ROW_NUMBER函数(可从MS SQL Server 2005获得):
WITH NumberedMyTable AS
(
SELECT
Id,
Value,
ROW_NUMBER() OVER (ORDER BY Id) AS RowNumber
FROM
MyTable
)
SELECT
Id,
Value
FROM
NumberedMyTable
WHERE
RowNumber BETWEEN @From AND @To
答案 1 :(得分:16)
此主题和网络上其他地方的建议存在的问题是,所有提议的解决方案都在相对于记录数的线性时间内运行。例如,请考虑以下查询。
select *
from
(
select
Row_Number() over (order by ClusteredIndexField) as RowNumber,
*
from MyTable
) as PagedTable
where RowNumber between @LowestRowNumber and @HighestRowNumber;
获取第1页时,查询需要0.577秒。但是,当获取第15,619页时,同样的查询需要2分55秒。
我们可以通过创建记录号,索引交叉表来大大改善这一点,如下面的查询所示。交叉表称为PagedTable,并且是非持久性的。
select *
from
(
select
Row_Number() over (order by Field1 asc, Field2 asc, Field3 asc) as RowNumber,
ClusteredIndexField
from MyTable
) as PagedTable
left join MyTable on MyTable.ClusteredIndexField = PagedTable.ClusteredIndexField
where RowNumber between @LowestRowNumber and @HighestRowNumber;
与上一个示例一样,我在一个包含780,928条记录的非常宽的表上测试了这个。我使用的页面大小为50,结果为15,619页。
第1页(第一页)所用的总时间为0.413秒。第15,619页(最后一页)所用的总时间为0.987秒,仅为第1页的两倍。这些时间是使用SQL Server Profiler测量的,DBMS是SQL Server 2008 R2。
当您按索引对表进行排序时,此解决方案适用于任何情况。索引不必是聚簇的或简单的。在我的例子中,索引由三个字段组成:varchar(50)asc,varchar(15)asc,numeric(19,0)asc。虽然繁琐的索引表现非常出色,但这进一步说明了这种方法的有效性。
但是,Row_Number窗口函数中的order by子句对应于索引是至关重要的。否则,性能将降低到与第一个示例相同的水平。
这种方法仍然需要线性操作来生成非持久性交叉表,但由于这只是一个添加了行号的索引,因此它很快就会发生。在我的情况下花了0.347秒,但我的案例有需要复制的varchars。单个数字索引将花费更少的时间。
出于所有实际目的,此设计减少了服务器端分页从线性操作到对数操作的扩展,允许扩展大型表。以下是完整的解决方案。
-- For a sproc, make these your input parameters
declare
@PageSize int = 50,
@Page int = 15619;
-- For a sproc, make these your output parameters
declare @RecordCount int = (select count(*) from MyTable);
declare @PageCount int = ceiling(convert(float, @RecordCount) / @PageSize);
declare @Offset int = (@Page - 1) * @PageSize;
declare @LowestRowNumber int = @Offset;
declare @HighestRowNumber int = @Offset + @PageSize - 1;
select
@RecordCount as RecordCount,
@PageCount as PageCount,
@Offset as Offset,
@LowestRowNumber as LowestRowNumber,
@HighestRowNumber as HighestRowNumber;
select *
from
(
select
Row_Number() over (order by Field1 asc, Field2 asc, Field3 asc) as RowNumber,
ClusteredIndexField
from MyTable
) as PagedTable
left join MyTable on MyTable.ClusteredIndexField = PagedTable.ClusteredIndexField
where RowNumber between @LowestRowNumber and @HighestRowNumber;
答案 2 :(得分:10)
在 SQL 2012 中,您可以使用$ ./echoserver.pl
Spawned PID 20953
Reaped PID 20953
bye
和OFFSET
:
FETCH
<小时/> 我个人更喜欢:
SELECT *
FROM MyTable
ORDER BY MyColumn
OFFSET @N ROWS
FETCH NEXT @M ROWS ONLY;
其中DECLARE @CurrentSetNumber int = 0;
DECLARE @NumRowsInSet int = 2;
SELECT *
FROM MyTable
ORDER BY MyColumn
OFFSET @NumRowsInSet * @CurrentSetNumber ROWS
FETCH NEXT @NumRowsInSet ROWS ONLY;
SET @CurrentSetNumber = @CurrentSetNumber + 1;
是您要返回的行数,@NumRowsInSet
是要跳过的@CurrentSetNumber
的数量。
答案 3 :(得分:8)
如果要从第25条记录中选择100条记录:
select TOP 100 * from TableName
where PrimaryKeyField
NOT IN(Select TOP 24 PrimaryKeyField from TableName);
答案 4 :(得分:5)
丑陋,hackish,但应该工作:
select top(M + N - 1) * from TableName
except
select top(N - 1) * from TableName
答案 5 :(得分:3)
对于小结果可能有用,适用于所有版本的TSQL:
SELECT
*
FROM
(SELECT TOP (N) *
FROM
(SELECT TOP (M + N - 1)
FROM
Table
ORDER BY
MyColumn) qasc
ORDER BY
MyColumn DESC) qdesc
ORDER BY
MyColumn
答案 6 :(得分:3)
-- *some* implementations may support this syntax (mysql?)
SELECT Id,Value
FROM xxx
ORDER BY Id
LIMIT 2 , 0
;
-- Separate LIMIT, OFFSET
SELECT Id,Value
FROM xxx
ORDER BY Id
LIMIT 2 OFFSET 2
;
-- SQL-2008 syntax
SELECT Id,Value
FROM xxx
ORDER BY Id
OFFSET 4
FETCH NEXT 2 ROWS ONLY
;
答案 7 :(得分:2)
@start = 3
@records = 2
Select ID, Value
From
(SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RowNum, ID,Value
From MyTable) as sub
Where sub.RowNum between @start and @start+@records
这是一种方式。如果你谷歌SQL分页,还有很多其他的。
答案 8 :(得分:2)
这个帖子很老了,但是目前你可以这样做: 更清洁的imho
SELECT *
FROM Sales.SalesOrderDetail
ORDER BY SalesOrderDetailID
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
GO
答案 9 :(得分:2)
为了在SQL Server中执行此操作,您必须按列排序查询,以便指定所需的行。
你不能使用&#34; TOP&#34;关键字在执行此操作时,必须使用偏移N行获取下一行M行。
示例:
select * from table order by [some_column]
offset 10 rows
FETCH NEXT 10 rows only
您可以在此处了解详情: https://technet.microsoft.com/pt-br/library/gg699618%28v=sql.110%29.aspx
答案 10 :(得分:1)
以下是简单查询将从表的第M + 1行列出N行。用您喜欢的号码替换M和N.
Select Top N B.PrimaryKeyColumn from
(SELECT
top M PrimaryKeyColumn
FROM
MyTable
) A right outer join MyTable B
on
A.PrimaryKeyColumn = B.PrimaryKeyColumn
where
A.PrimaryKeyColumn IS NULL
请告诉我这是否对您的情况有用。
答案 11 :(得分:1)
这就是如何在没有主键的表上实现相同的目标:
select * from
(
select row_number() over(order by (select 0)) rowNum,*
from your_table
) tmp
where tmp.rowNum between 20 and 30 -- any numbers you need
答案 12 :(得分:1)
我在这里阅读了所有的回复,最后提出了一个简单易用的解决方案。性能问题来自BETWEEN语句,而不是行号本身的生成。所以我使用算法通过传递页码和记录数来进行动态分页。
传递不是开始行和行数,而是&#34;每页行数(500)&#34;和&#34;页码(4)&#34;这些值可以是行1501 - 2000.这些值可以由存储过程变量替换,因此您不会被锁定使用特定的分页量。
select * from (
select
(((ROW_NUMBER() OVER(ORDER BY MyField) - 1) / 500) + 1) AS PageNum
, *
from MyTable
) as PagedTable
where PageNum = 4;
答案 13 :(得分:0)
为什么不进行两次查询:
select top(M+N-1) * from table into temp tmp_final with no log;
select top(N-1) * from tmp_final order by id desc;
答案 14 :(得分:0)
T-SQL
有一个非常简单的方法,但如果你跳过大量的行,我不确定它是否是预先有效的。
SELECT TOP numberYouWantToTake
[yourColumns...]
FROM yourTable
WHERE yourIDColumn NOT IN (
SELECT TOP numberYouWantToSkip
yourIDColumn
FROM yourTable
ORDER BY yourOrderColumn
)
ORDER BY yourOrderColumn
如果你正在使用.Net,你可以使用以下内容,例如IEnumerable和你的数据结果:
IEnumerable<yourDataType> yourSelectedData = yourDataInAnIEnumerable.Skip(nubmerYouWantToSkip).Take(numberYouWantToTake);
这样做的背后是你从数据存储中获取所有数据。
答案 15 :(得分:0)
SELECT * FROM (
SELECT
Row_Number() Over (Order by (Select 1)) as RawKey,
*
FROM [Alzh].[dbo].[DM_THD_TRANS_FY14]
) AS foo
WHERE RawKey between 17210400 and 17210500
答案 16 :(得分:0)
查找第N行的ID 然后获取id大于或等于
的前M行declare @N as int set @N = 2 declare @M as int set @M = 3 declare @Nid as int set @Nid = max(id) from (select top @N * from MyTable order by id) select top @M * from MyTable where id >= @Nid order by id
类似的东西......但我在这里做了一些假设(例如你想按id订购)