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

为什么我的带有OFFSET/FETCH的SQL语句不起作用?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我使用的是SQL Server,在购买表中,我有大约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 DES

我使用的是SQL Server,在购买表中,我有大约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
前两个命令返回的记录完全相同。 为什么它们不显示两组不同的结果


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

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

所以,如果您想要20行,那么您将始终只获取接下来的20行

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

我将重新编写为

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

如果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

@狗仔队已经弄明白了这一点,但也许我可以对他们的答案做一点扩展

如果表中的任意两条记录具有相同的PurchaseDate,则不会使用ORDER BY PurchaseDate子句,因为无论SQL Server选择首先返回这两条记录中的哪一条,都将满足订购要求。在您的情况下,由于所有记录都具有相同的购买日期,SQL Server可以按任何顺序返回这些记录,因此该子句将得到满足。换句话说,您的ORDERBY子句没有任何用途,除非您需要有一个子句才能使用OFFSET…FETCH

因为您无法确切地知道ORDERBY子句将生成什么样的顺序,所以您也无法知道特定的偏移量将把您放在该顺序中的什么位置,这意味着您无法知道三个查询中的任何一个都将返回哪些记录。SQL Server为前两个查询中的每个查询返回相同的结果集是合法行为,但即使如此也不能保证每次都会发生;你也可以很容易地得到不同的结果

如果您需要保证这样的查询将返回不相交的集合,那么您需要编写ORDERBY子句,这样就不会有两个记录具有相同的字段值组合。在您的例子中,您说每行都有一个唯一的标识符,所以您可以先按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,那么我就不需要在ORDER BY子句中包含RowNumber来获得不相交的集合,因为单是PurchaseDate就足以保证唯一的订购。

提示:只取下20行。但为什么它根本不偏移?前两个命令返回相同的结果。我认为偏移量20意味着跳过所选内容的前20条记录,然后FETCH将从中获取数据。第三个命令返回不同的行还是根本不返回行?第三个命令返回不同的结果集。选择表中剩余的内容。这个看起来不错。但前两个仍然返回相同的结果集。所有的记录都是唯一的,所以它们应该返回完全不同的记录集。。。但他们还是回到了同一组。我很酷,分数对我来说并不重要。我不是在批评。只是一个评论。狗仔队说:“如果我对某人的答案进行详细阐述,我总是+1。谢谢你的评论。”。我通常也会这样做,如果我认为有些事情需要澄清,我会添加一条评论而不是一个新的答案。在这种情况下,我认为你的答案虽然正确,但足够简洁,如果我不知道发生了什么,我就不会理解。但你是第一个得出正确答案的人,我看到你在答案上加了一点,所以对你来说+1谢谢你救了我的命!