SQL Server中是否有任何方法可以从给定的偏移量开始获取结果?例如,在另一种类型的SQL数据库中,可以执行以下操作:
SELECT * FROM MyTable OFFSET 50 LIMIT 25
获得结果51-75。此构造似乎不存在于SQL Server中。
如何在不加载我不关心的所有行的情况下完成此操作?谢谢!
答案 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_NUMBER
和BETWEEN
对于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)
根据您的版本,您不能直接执行,但您可以做一些像
这样的hackyselect 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;
注意 OFFSET指定要跳过的行数,然后开始从查询表达式返回行。它不是起始行号。因此,包含第一条记录必须为0。