SQL Server中的行偏移量

Row Offset in SQL Server

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

1
SELECT * FROM MyTable OFFSET 50 LIMIT 25

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

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


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

SQL Server 2005+

1
2
3
4
5
6
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

通过SQL Server 2000中的大型结果集进行高效分页

一种更有效的大结果集寻呼方法


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

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

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

1
2
3
4
5
SELECT  *
FROM     MyTable
ORDER BY OrderingColumn ASC
OFFSET  50 ROWS
FETCH NEXT 25 ROWS ONLY

虽然这个选项的表现有多好还有待观察。


这是一种方式(SQL2000)

1
2
3
4
5
6
7
8
9
10
11
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)

1
2
3
4
5
6
7
8
9
;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


您可以使用ROW_NUMBER()函数来获得所需内容:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
);

-

1
2
3
[CONDITION] can contain any WHERE clause FOR searching.
[OFFSET] specifies the START,
[LIMIT] the maximum results.

它在具有大数据的表(如BLOB)上具有更好的性能,因为ROW_NUMBER函数只需查看一列,并且只返回匹配的行与所有列。


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

如果你真的没有任何可以作为ORDER BY列传递的显式列(正如其他人建议的那样),那么你可以使用这个技巧:

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

... 要么

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

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


请参阅我的select for paginator

1
2
3
4
5
6
7
8
9
10
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

这解决了分页;)


1
2
3
SELECT TOP 75 * FROM MyTable
EXCEPT
SELECT TOP 50 * FROM MyTable


根据你的版本,你不能直接做,但你可以做一些像hacky这样的事情

1
2
3
4
5
6
7
SELECT top 25 *
FROM (
  SELECT top 75 *
  FROM   TABLE
  ORDER BY FIELD ASC
) a
ORDER BY FIELD DESC

其中'field'是关键。


使用ROW_NUMBER() OVER (ORDER BY)语句时应该小心,因为性能很差。使用与ROW_NUMBER()的公用表表达式相同甚至更糟。我使用的代码片段已经证明比使用带有标识的表变量稍快一些,以提供页码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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


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

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

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


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

该表具有以下内容:

1
ID, KeyId, Rank

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

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

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

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

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

这对系统的压力最小


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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)


不浪费时间订购记录的最佳方式是这样的:

1
SELECT 0 AS tmp,Column1 FROM Table1 ORDER BY tmp OFFSET 5000000 ROWS FETCH NEXT 50 ROWS ONLY

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


最简单的方法是

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

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


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

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

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

1
2
3
4
5
6
7
8
9
10
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