SQL Server选择最后N行


139

这是一个已知的问题,但是我发现的最佳解决方案是:

SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

我的桌子上有很多行。使用该查询不是一种可能,因为它会花费很多时间。那么如何在不使用ORDER BY的情况下选择最后N行呢?

编辑

对不起,这个重复的问题


“最后N个”是什么意思?没有命令,“最后N”没有太大意义。如果您的意思是“要插入的最后一个N”,则不能依靠SQL Server来提供它-您必须使用ORDER BY子句。
丹尼尔·伦肖

@Daniel Renshaw:该表的最后N个而不强制SQL Server对所有表进行排序,因为它的运行速度非常慢
Diego 2010年

您问题中的查询最好的方法。如果id已建立索引,则它将反向扫描该索引,并在前5行之后停止。如果未索引,则需要进行TOP N排序。这不会比其他任何方式都要糟糕。它不会对整个表进行排序(尽管它需要扫描整个表)
Martin Smith

Answers:


38

您也可以使用“按分区行数”功能来完成此操作。一个很好的例子可以在这里找到:

我正在使用Northwind数据库的Orders表...现在让我们检索Employee 5下的最后5个订单:

SELECT ORDERID, CUSTOMERID, OrderDate
FROM
(
    SELECT ROW_NUMBER() OVER (PARTITION BY EmployeeID ORDER BY OrderDate DESC) AS OrderedDate,*
    FROM Orders
) as ordlist

WHERE ordlist.EmployeeID = 5
AND ordlist.OrderedDate <= 5

1
ROW NUMBER BY PARTITION功能也使用排序..您需要对表进行排序以为每条记录分配行号...
Sadhir 2010年

的确是这样,但是如果没有某种性质,它根本就行不通,最好的解决方案是对命中的主要列建立索引并使用上述查询来运行。
JonVD 2010年

101

您可以使用以下SQL使SQL Server选择最后N行:

select * from tbl_name order by id desc limit N;

2
版本兼容性如何?
Fractaliste

63
这在SQL Server中不起作用。好像是MySQL,PostgreSQL和SQLite功能。
Tim Friesen 2014年

3
所有枚举产品绝对是SQL Server。如果您想谈论MS SQL Server,为什么不这样命名呢?
gena2x

4
我很困惑,该问题询问如何“不使用ORDER BY”创建选择查询,并且答案中的选择查询具有“ order by”。这是某种“排序依据”而不是“排序依据”吗?
罗伯特·辛克莱

5
@ gena2x这个问题标记为SQL Server。该标记引用Microsoft SQL Server。
马丁·史密斯

51

我测试了JonVD的代码,但发现它很慢,只有6s。

这段代码用了0s。

SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders where EmployeeID=5    
Order By OrderDate DESC

4
多少行?当您有很多行可能真的很慢时
迭戈

@Diego为什么?如果您已建立OrderDate索引,从本质上来说,选择查询的 N行或后 N行应该同样快。我意识到有机会OrderDate与插入的订单很好地关联,但这充其量是副作用,仍然需要进行表扫描,对吗?(我不认为这可以回答OP所指出的问题的更好表达:即不进行排序)
ruffin

1
@迭戈-为什么您会认为这比您接受的答案要慢?
马丁·史密斯

2
这将使行倒置。然后,您必须由他们重新订购才能恢复原始订单。
标记

15

如果要从表中选择最后的行数。

语法会像

 select * from table_name except select top 
 (numbers of rows - how many rows you want)* from table_name

这些陈述有效,但方式不同。感谢你们。

 select * from Products except select top (77-10) * from Products

这样,您可以获得最后10行,但顺序将显示降序方式

select top 10 * from products
 order by productId desc 

 select * from products
 where productid in (select top 10 productID from products)
 order by productID desc

 select * from products where productID not in 
 (select top((select COUNT(*) from products ) -10 )productID from products)

7

在一般情况下,为了支持SQL Server,这里是

SELECT TOP(N) *
FROM tbl_name
ORDER BY tbl_id DESC

并且对于性能来说还不错(服务器计算机上的10,000条记录少于一秒钟)


1
10 000条记录对于您而言应该没有什么影响。当您开始谈论数百万条记录时,您就可以开始考虑性能
Dom84'4

6

是否将“ Id”编入索引?如果没有,那是一件重要的事情(我怀疑它已经被索引了)。

另外,您是否需要返回ALL列?如果您实际上只需要一个较小的列子集,而这些子集可以完全由ID列上的索引满足,例如,如果您在Id列上具有NONCLUSTERED索引,而没有其他列,则可能会大大提高速度索引中包含的字段,则必须对聚簇索引进行查找才能实际获取其余列以返回,这可能会占用大量查询费用。如果它是CLUSTERED索引,或者是包含要在查询中返回的所有其他字段的NONCLUSTERED索引,那么应该没问题。


6

首先,您最多会从

 Declare @TableRowsCount Int
 select @TableRowsCount= COUNT(*) from <Your_Table>

然后 :

在SQL Server 2012中

SELECT *
FROM  <Your_Table> As L
ORDER BY L.<your Field>
OFFSET <@TableRowsCount-@N> ROWS
FETCH NEXT @N ROWS ONLY;

在SQL Server 2008中

SELECT *
FROM 
(
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS sequencenumber, *
FROM  <Your_Table>
    Order By <your Field>
) AS TempTable
WHERE sequencenumber > @TableRowsCount-@N 

4

您可以尝试以下操作而无需使用,order by但我认为这要求每一行都是唯一的。 N是所需的行数,L是表中的行数。

select * from tbl_name except select top L-N * from tbl_name

如前所述,返回的行是不确定的。

编辑:这实际上是狗慢。真的没有价值。


4
select * from (select top 6 * from vwTable order by Hours desc) T order by Hours

2

该查询以正确的顺序返回最后N行,但性能不佳

select *
from (
    select top N *
    from TableName t
    order by t.[Id] desc
) as temp
order by temp.[Id]

2

在查询末尾将desc与orderby一起使用以获取最后一个值。


1

这可能不太适合该问题,但是…

OFFSET子句

OFFSET number子句使您可以跳过许多行,然后在那之后返回行。

该文档链接指向Postgres。我不知道这是否适用于Sybase / MS SQL Server。


1
DECLARE @MYVAR  NVARCHAR(100)
DECLARE @step  int
SET @step = 0;


DECLARE MYTESTCURSOR CURSOR
DYNAMIC 
FOR
SELECT col FROM [dbo].[table]
OPEN MYTESTCURSOR
FETCH LAST FROM MYTESTCURSOR INTO @MYVAR
print @MYVAR;


WHILE @step < 10
BEGIN   
    FETCH PRIOR FROM MYTESTCURSOR INTO @MYVAR
        print @MYVAR;
        SET @step = @step + 1;
END   
CLOSE MYTESTCURSOR
DEALLOCATE MYTESTCURSOR

1

MS在t-sql中不支持LIMIT。大多数时候,我只是得到MAX(ID)然后减去。

select * from ORDERS where ID >(select MAX(ID)-10 from ORDERS)

当ID不连续时,它将返回少于10条记录。


0

我用来查询非常大的表(100+百万或1+十亿行)中最最近的行的一种技术限制为仅“读取”最近行的“ N”百分比。这是真实的应用程序,例如,我对非历史性的“最近的天气”数据,“最近的”新闻提要搜索或“最近的GPS”位置数据点数据执行此操作。

例如,如果您确定您的行位于表的最新TOP 5%中,那么这将是巨大的性能改进。这样,即使在表上有索引,它也进一步将可能性限制为表中具有100+万或1+十亿行的行的5%。当较旧的数据将需要物理磁盘读取而不仅是逻辑内存写入时,尤其是在这种情况下读取。

这比SELECT TOP |效率更高。PERCENT | LIMIT(限制),因为它不选择行,而仅限制要搜索的数据部分。

DECLARE @RowIdTableA BIGINT
DECLARE @RowIdTableB BIGINT
DECLARE @TopPercent FLOAT

-- Given that there is an Sequential Identity Column
-- Limit query to only rows in the most recent TOP 5% of rows
SET @TopPercent = .05
SELECT @RowIdTableA = (MAX(TableAId) - (MAX(TableAId) * @TopPercent)) FROM TableA
SELECT @RowIdTableB = (MAX(TableBId) - (MAX(TableBId) * @TopPercent)) FROM TableB

SELECT *
FROM TableA a
INNER JOIN TableB b ON a.KeyId = b.KeyId
WHERE a.Id > @RowIdTableA AND b.Id > @RowIdTableB AND
      a.SomeOtherCriteria = 'Whatever'

-1

要显示最后三行而不使用order by

select * from Lms_Books_Details where Book_Code not in 
 (select top((select COUNT(*) from Lms_Books_Details ) -3 ) book_code from Lms_Books_Details) 

1
这将不会提供可预测的结果。根据Sql Server MSDN文档(msdn.microsoft.com/en-us/library/ms189463.aspx):“当TOP与ORDER BY子句一起使用时,结果集限于有序的前N个数行;否则,它将以未定义的顺序返回前N个行。”
Caveman_dick 2012年


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.