SQL Server SELECT最后N行

SQL Server SELECT LAST N Rows

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

1
2
3
SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

我有一张有很多行的桌子。使用该查询不是一种可能性,因为它需要很多时间。那么,如何在不使用order by的情况下选择最后n行呢?

编辑

抱歉,重复了这个问题


可以使SQL Server使用此SQL选择最后n行:

1
SELECT * FROM tbl_name ORDER BY id DESC LIMIT N;


我测试了Jonvd的代码,但发现它非常慢,6秒。

这段代码花了0秒。

1
2
3
SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders WHERE EmployeeID=5    
ORDER BY OrderDate DESC


您也可以通过使用按分区的行数功能来实现这一点。这里有一个很好的例子:

I am using the Orders table of the Northwind database... Now let us retrieve the Last 5 orders placed by Employee 5:

1
2
3
4
5
6
7
8
9
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
2
 SELECT * FROM TABLE_NAME EXCEPT SELECT top
 (numbers OF ROWS - how many ROWS you want)* FROM TABLE_NAME

这些说法有效,但方式不同。谢谢你们。

1
 SELECT * FROM Products EXCEPT SELECT top (77-10) * FROM Products

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

1
2
SELECT top 10 * FROM products
 ORDER BY productId DESC

1
2
3
 SELECT * FROM products
 WHERE productid IN (SELECT top 10 productID FROM products)
 ORDER BY productID DESC
1
2
 SELECT * FROM products WHERE productID NOT IN
 (SELECT top((SELECT COUNT(*) FROM products ) -10 )productID FROM products)


"id"被索引了吗?如果没有,这是一件重要的事情要做(我怀疑它已经被索引了)。

另外,是否需要返回所有列?如果您实际上只需要ID列上的索引能够完全满足的列的较小子集(例如,如果ID列上有一个非聚集索引,索引中不包含其他字段),那么您可能会在速度上得到很大的提高,然后它将不得不对聚集索引进行查找,以实际获得T。他返回其余的列,这可能会构成查询的大量成本。如果它是聚集索引,或者是包含查询中要返回的所有其他字段的非聚集索引,那么应该可以。


以非常一般的方式,为了支持SQL Server,这里是

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

性能还不错(服务器上10000多条记录不到一秒钟)


首先,你最多从

1
2
 DECLARE @TableRowsCount INT
 SELECT @TableRowsCount= COUNT(*) FROM <Your_Table>

然后:

在SQL Server 2012中

1
2
3
4
5
SELECT *
FROM  <Your_Table> AS L
ORDER BY L.<your Field>
OFFSET <@TableRowsCount-@N> ROWS
FETCH NEXT @N ROWS ONLY;

在SQL Server 2008中

1
2
3
4
5
6
7
8
SELECT *
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY ID) AS sequencenumber, *
FROM  <Your_Table>
    ORDER BY <your Field>
) AS TempTable
WHERE sequencenumber > @TableRowsCount-@N


这里有一些没有order by你可以尝试的东西,但是我认为它要求每一行都是唯一的。N是所需的行数,L是表中的行数。

1
SELECT * FROM tbl_name EXCEPT SELECT top L-N * FROM tbl_name

如前所述,返回哪些行是未定义的。

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


1
SELECT * FROM (SELECT top 6 * FROM vwTable ORDER BY Hours DESC) T ORDER BY Hours

在查询结束时使用DESC和ORDERBY获取最后一个值。


此查询以正确的顺序返回最后n行,但性能较差

1
2
3
4
5
6
7
SELECT *
FROM (
    SELECT top N *
    FROM TableName t
    ORDER BY t.[Id] DESC
) AS temp
ORDER BY temp.[Id]


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

抵消条款

OFFSET number子句使您能够跳过许多行,然后返回后面的行。

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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亿多行或10亿多行)的一种技术将查询限制为"读取"最近行中最新的"n"百分比。这是真实世界的应用程序,例如,我对非历史最近的天气数据、最近的新闻提要搜索或最近的GPS位置数据点数据执行此操作。

例如,如果您确定您的行位于表的最新前5%中,那么这是一个巨大的性能改进。这样,即使表上有索引,它也会进一步限制表中具有1亿或10亿行的行的可能性仅为5%。尤其是当旧数据需要物理磁盘读取,而不仅仅是逻辑内存读取时。

这比选择top percent limit更有效,因为它不选择行,只限制要搜索的数据部分。

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


不使用order by显示最后3行:

1
2
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)


尝试使用EXCEPT语法。像这样:

1
2
3
4
5
   SELECT *
    FROM   clientDetails
    EXCEPT
    (SELECT TOP (numbers OF ROWS - how many ROWS you want) *
     FROM   clientDetails)