为什么我的OFFSET / FETCH的SQL语句不起作用?

时间:2018-05-04 15:43:13

标签: sql sql-server tsql

我正在使用SQL Server,在表Purchase中,我有大约50条记录。 我试图获取前20(0-20),然后20-40,最后是最后10。

我拥有的SQL命令是:

SELECT * FROM Purchase WHERE dataOK = 'OK' ORDER BY PurchaseDate DESC OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY

SELECT * FROM Purchase WHERE dataOK = 'OK' ORDER BY PurchaseDate DESC OFFSET 19 ROWS FETCH NEXT 20 ROWS ONLY

SELECT * FROM Purchase WHERE dataOK = 'OK' ORDER BY PurchaseDate DESC OFFSET 39 ROWS FETCH NEXT 20 ROWS ONLY

我不知道为什么,但前两个命令返回完全相同的记录。 为什么它没有显示两组不同的结果?

编辑: 好的,我知道XX中的FETCH XX是要返回的行数。但是我的SQL服务器返回的结果与上面的前两个命令完全相同。

4 个答案:

答案 0 :(得分:1)

返回的行数由命令的FETCH部分确定。这是行数。它不是偏移的位置。

因此,如果您想要20行,那么您将始终拥有FETCH NEXT 20 ROWS ONLY

前两个不应该返回相同的结果。 。 。虽然如果只看PurchaseDate,某些结果可能看起来相同。

答案 1 :(得分:1)

如果PurchaseDate不是唯一的,那么该组中的订单不能保证重复 将ID添加到排序中以获得可重复的排序。

SELECT * FROM Purchase WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC, ID 
OFFSET  0 ROWS FETCH NEXT 20 ROWS ONLY

SELECT * FROM Purchase WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC, ID 
OFFSET 19 ROWS FETCH NEXT 20 ROWS ONLY

SELECT * FROM Purchase WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC, ID 
OFFSET 39 ROWS FETCH NEXT 20 ROWS ONLY

答案 2 :(得分:0)

我会重写为

SELECT * 
FROM Purchase 
WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY
GO
SELECT * 
FROM Purchase 
WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC OFFSET 19 ROWS FETCH NEXT 21 ROWS ONLY
SELECT * 
FROM Purchase 
WHERE dataOK = 'OK' 
ORDER BY PurchaseDate DESC OFFSET 40 ROWS FETCH NEXT 10 ROWS ONLY

答案 3 :(得分:0)

@paparazzo已经解决了这个问题,但也许我可以稍微扩展他们的答案。

如果表中的任何两条记录具有相同的ORDER BY PurchaseDate,则PurchaseDate子句将不是deterministic,因为无论SQL Server中的哪两条记录,仍然会满足排序选择先退回。在您的情况下,由于所有记录具有相同的PurchaseDate,因此SQL Server可以在任何顺序中返回这些记录,并且该子句将得到满足。换句话说,您的ORDER BY条款没有任何意义,除非您需要使用OFFSET...FETCH条款才能​​使用ORDER BY

因为您无法准确知道OFFSET子句将产生什么排序,您也无法知道特定ORDER BY将在哪个排序中进行排序,这意味着您无法知道哪些记录将会由三个查询的任何返回。 SQL Server为前两个查询返回相同的结果集是合法行为,但即使这样也不能保证每次都发生;你可以很容易地得到不同的结果。

如果您需要保证此类查询将返回不相交的集合,那么您需要编写PurchaseDate子句,使得没有两个记录对您要订购的字段具有相同的值组合。在您的情况下,您说每行有一个唯一标识符,因此您可以先按-- Create sample data: 50 records with unique RowNumber values and the same PurchaseDate value. declare @Purchase table (RowNumber int, PurchaseDate date); with Numbers as (select top 50 RowNumber = row_number() over (order by (select null)) from sys.objects) insert @Purchase select RowNumber, PurchaseDate = /*dateadd(day, RowNumber,*/ convert(date, getdate())/*)*/ from Numbers; -- These result sets are nondeterministic because all the PurchaseDate values are the same, which -- means that the records may be returned in any order and the ORDER BY will be satisfied. select * from @Purchase order by PurchaseDate offset 0 rows fetch next 20 rows only; select * from @Purchase order by PurchaseDate offset 20 rows fetch next 20 rows only; select * from @Purchase order by PurchaseDate offset 40 rows fetch next 20 rows only; -- Adding the unique RowNumber to my ORDER BY clause makes the results deterministic and therefore -- guarantees that the following result sets will be rows 1-20, 21-40, and 41-50, respectively. select * from @Purchase order by PurchaseDate, RowNumber offset 0 rows fetch next 20 rows only; select * from @Purchase order by PurchaseDate, RowNumber offset 20 rows fetch next 20 rows only; select * from @Purchase order by PurchaseDate, RowNumber offset 40 rows fetch next 20 rows only; 排序,然后按该标识符排序,您的查询将适用于您。这是一个例子:

PurchaseDate

请注意,如果我要取消注释分配PurchaseDate值的行的已注释部分,这会为每行提供唯一的RowNumber,那么我就不需要包含{我的ORDER BY子句中的{1}}是为了得到不相交的集合,因为仅PurchaseDate就足以保证唯一的排序。