SQL Server中的行偏移量

时间:2008-10-09 16:13:04

标签: sql sql-server

SQL Server中是否有任何方法可以从给定的偏移量开始获取结果?例如,在另一种类型的SQL数据库中,可以执行以下操作:

SELECT * FROM MyTable OFFSET 50 LIMIT 25

获得结果51-75。此构造似乎不存在于SQL Server中。

如何在不加载我不关心的所有行的情况下完成此操作?谢谢!

17 个答案:

答案 0 :(得分:150)

我会避免使用SELECT *。指定您真正想要的列,即使它们可能都是。

SQL Server 2005 +

SELECT col1, col2 
FROM (
    SELECT col1, col2, ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
    FROM MyTable
) AS MyDerivedTable
WHERE MyDerivedTable.RowNum BETWEEN @startRow AND @endRow

SQL Server 2000

Efficiently Paging Through Large Result Sets in SQL Server 2000

A More Efficient Method for Paging Through Large Result Sets

答案 1 :(得分:95)

如果您要按顺序处理所有页面,那么只记住上一页上看到的最后一个键值并使用TOP (25) ... WHERE Key > @last_key ORDER BY Key可以是性能最佳的方法,如果存在合适的索引以允许有效地搜索 - 或者an API cursor如果他们不这样做。

对于选择仲裁页面,SQL Server 2005 - 2008 R2的最佳解决方案可能是ROW_NUMBERBETWEEN

对于SQL Server 2012+,您可以使用增强的ORDER BY子句来满足此需求。

SELECT  *
FROM     MyTable 
ORDER BY OrderingColumn ASC 
OFFSET  50 ROWS 
FETCH NEXT 25 ROWS ONLY 

虽然it remains to be seen how well performing this option will be

答案 2 :(得分:22)

这是一种方式(SQL2000)

SELECT * FROM
(
    SELECT TOP (@pageSize) * FROM
    (
        SELECT TOP (@pageNumber * @pageSize) *
        FROM tableName 
        ORDER BY columnName ASC
    ) AS t1 
    ORDER BY columnName DESC
) AS t2 
ORDER BY columnName ASC

这是另一种方式(SQL 2005)

;WITH results AS (
    SELECT 
        rowNo = ROW_NUMBER() OVER( ORDER BY columnName ASC )
        , *
    FROM tableName 
) 
SELECT * 
FROM results
WHERE rowNo between (@pageNumber-1)*@pageSize+1 and @pageNumber*@pageSize

答案 3 :(得分:10)

您可以使用ROW_NUMBER()功能获得所需内容:

SELECT *
FROM (SELECT ROW_NUMBER() OVER(ORDER BY id) RowNr, id FROM tbl) t
WHERE RowNr BETWEEN 10 AND 20

答案 4 :(得分:6)

对于包含更多和更大数据列的表,我更喜欢:

SELECT 
  tablename.col1,
  tablename.col2,
  tablename.col3,
  ...
FROM
(
  (
    SELECT
      col1
    FROM 
    (
      SELECT col1, ROW_NUMBER() OVER (ORDER BY col1 ASC) AS RowNum
      FROM tablename
      WHERE ([CONDITION])
    )
    AS T1 WHERE T1.RowNum BETWEEN [OFFSET] AND [OFFSET + LIMIT]
  )
  AS T2 INNER JOIN tablename ON T2.col1=tablename.col1
);

-

[CONDITION] can contain any WHERE clause for searching.
[OFFSET] specifies the start,
[LIMIT] the maximum results.

对于像BLOB这样的大数据表,它具有更好的性能,因为ROW_NUMBER函数只需查看一列,并且只返回匹配的所有列。

答案 5 :(得分:6)

SQL Server 2012中有OFFSET .. FETCH,但您需要指定ORDER BY列。

如果您确实没有任何明确的列可以作为ORDER BY列传递(正如其他人建议的那样),那么您可以使用此技巧:

SELECT * FROM MyTable 
ORDER BY @@VERSION 
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

......或

SELECT * FROM MyTable 
ORDER BY (SELECT 0)
OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY

当用户未明确指定订单时,我们会在jOOQ中使用它。这将产生相当随机的顺序,而无需任何额外费用。

答案 6 :(得分:5)

请参阅我的select for paginator

SELECT TOP @limit * FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY colunx ASC) offset, * FROM (

     -- YOU SELECT HERE
     SELECT * FROM mytable


   ) myquery
) paginator
WHERE offset > @offset

这解决了分页问题;)

答案 7 :(得分:3)

SELECT TOP 75 * FROM MyTable
EXCEPT 
SELECT TOP 50 * FROM MyTable

答案 8 :(得分:2)

使用row_number()OVER(ORDER BY)语句时应该小心,因为performane非常差。使用带有row_number()的公用表表达式更是如此。我使用的代码片段已经证明比使用带有标识的表变量稍快一些,以提供页码。

DECLARE @Offset INT = 120000
DECLARE @Limit INT = 10

DECLARE @ROWCOUNT INT = @Offset+@Limit
SET ROWCOUNT @ROWCOUNT

SELECT * FROM MyTable INTO #ResultSet
WHERE MyTable.Type = 1

SELECT * FROM
(
    SELECT *, ROW_NUMBER() OVER(ORDER BY SortConst ASC) As RowNumber FROM
    (
        SELECT *, 1 As SortConst FROM #ResultSet
    ) AS ResultSet
) AS Page
WHERE RowNumber BETWEEN @Offset AND @ROWCOUNT

DROP TABLE #ResultSet

答案 9 :(得分:2)

根据您的版本,您不能直接执行,但您可以做一些像

这样的hacky
select top 25 *
from ( 
  select top 75 *
  from   table 
  order by field asc
) a 
order by field desc 

其中'field'是关键。

答案 10 :(得分:2)

以下将显示25条记录,不包括SQL Server 2012中的前50条记录。

SELECT * FROM MyTable ORDER BY ID OFFSET 50 ROWS FETCH NEXT 25 ROWS ONLY;

您可以将ID替换为您的要求

答案 11 :(得分:1)

我使用这种技术进行分页。我没有获取所有行。例如,如果我的页面需要显示前100行,我只使用where子句获取100。 SQL的输出应该有一个唯一的密钥。

该表格如下:

ID, KeyId, Rank

将为多个KeyId分配相同的排名。

SQL是select top 2 * from Table1 where Rank >= @Rank and ID > @Id

我第一次为两者传球0。第二次通过1& 14.第3次传球2和6 ......

第10个记录的价值排名& ID传递给下一个

11  21  1
14  22  1
7   11  1
6   19  2
12  31  2
13  18  2

这对系统的压力最小

答案 12 :(得分:1)

在SqlServer2005中,您可以执行以下操作:

DECLARE @Limit INT
DECLARE @Offset INT
SET @Offset = 120000
SET @Limit = 10

SELECT 
    * 
FROM
(
   SELECT 
       row_number() 
   OVER 
      (ORDER BY column) AS rownum, column2, column3, .... columnX
   FROM   
     table
) AS A
WHERE 
 A.rownum BETWEEN (@Offset) AND (@Offset + @Limit-1) 

答案 13 :(得分:1)

最好的办法是在不浪费时间订购记录的情况下这样做:

select 0 as tmp,Column1 from Table1 Order by tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY

只需不到一秒钟! 大表的最佳解决方案。

答案 14 :(得分:0)

我一直在寻找这个答案一段时间(用于通用查询),并找到了使用ROWCOUNT和游标以及没有TOP或任何临时表在SQL Server 2000+上执行此操作的另一种方法。

使用SET ROWCOUNT [OFFSET+LIMIT]可以限制结果,并使用游标直接转到您想要的行,然后循环直到结束。

所以你的查询会是这样的:

SET ROWCOUNT 75 -- (50 + 25)
DECLARE MyCursor SCROLL CURSOR FOR SELECT * FROM pessoas
OPEN MyCursor
FETCH ABSOLUTE 50 FROM MyCursor -- OFFSET
WHILE @@FETCH_STATUS = 0 BEGIN
    FETCH next FROM MyCursor
END
CLOSE MyCursor
DEALLOCATE MyCursor
SET ROWCOUNT 0

答案 15 :(得分:0)

最简单的方法是

SELECT * FROM table ORDER BY OrderColumn ASC LIMIT 50,25;

这适用于MySQL和(我认为)其他SQL数据库。

答案 16 :(得分:0)

对于SQL Server 2012(11.x)和更高版本以及Azure SQL数据库,您还可以具有“ fetch_row_count_expression”,还可以具有ORDER BY子句。

USE AdventureWorks2012;  
GO  
-- Specifying variables for OFFSET and FETCH values    
DECLARE @skip int = 0  , @take int = 8;  
SELECT DepartmentID, Name, GroupName  
FROM HumanResources.Department  
ORDER BY DepartmentID ASC   
    OFFSET @skip ROWS   
    FETCH NEXT @take ROWS ONLY; 

https://docs.microsoft.com/en-us/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-ver15

注意 OFFSET指定要跳过的行数,然后开始从查询表达式返回行。它不是起始行号。因此,包含第一条记录必须为0。