214

This is a known question but the best solution I've found is something like:

SELECT TOP N * FROM MyTable ORDER BY Id DESC 

I've a table with lots of rows. It is not a posibility to use that query because it takes lot of time. So how can I do to select last N rows without using ORDER BY?

EDIT

Sorry duplicated question of this one

6
  • What is meant by "last N"? Without an order, "last N" doesn't make much sense. If you mean "last N to be inserted" then you can't rely on SQL Server to give that to you - you must use an ORDER BY clause. Commented Nov 16, 2010 at 12:16
  • @Daniel Renshaw: The last N of the table without forcing SQL Server to order all table because it gets really slow Commented Nov 16, 2010 at 12:30
  • 2
    The query in your question is the best way. If id is indexed then it will just scan that index in reverse and stop after the first 5 rows. If it is not indexed then it will need to do a TOP N sort. This won't be worse than any other way of doing it. It doesn't sort the whole table (though it would need to scan the whole table) Commented Sep 28, 2012 at 7:37
  • Why did you mark the answer with a partition, which uses ordering, as the accepted answer? It is no better than your original query. All it does it add nuance to the query - i.e. last N by a particular customer. Your query does not require any partitioning. Commented Aug 16, 2021 at 23:37
  • @onefootswill In my experience, using ROW_NUMBER OVER PARTITION BY for this type of query in MS SQL Server is much, much faster that the other methods. So I for one am happy that it got marked as the accepted answer, all other things being equal. Commented Jun 27, 2023 at 7:39

23 Answers 23

163

You can get MySQL, PostgreSQL, and SQLite (but not SQL Server) to select the last N rows with the following query:

select * from tbl_name order by id desc limit N; 
Sign up to request clarification or add additional context in comments.

8 Comments

How about version compatibility?
This does not work in SQL Server. Seems like a MySQL, PostgreSQL, and SQLite feature.
All enumerated products are definetly SQL servers. If you want to talk about MS SQL server, why not name it so?
i'm confused, the question asks how to create a select query "without using ORDER BY" and the select query in your answer has "order by". Is this some kind of an "order by" without "order by"?
@gena2x this question is tagged SQL Server. That tag refers to Microsoft SQL Server.
|
66

I tested JonVD's code, but found it was very slow, 6s.

This code took 0s.

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

4 Comments

How many rows?? When you've got lot of rows that can be REALY slow
@Diego Why is that? If you've got OrderDate indexed, it should be essentially equally quick to pick the first or last N rows of a query. I realize there's a chance OrderDate correlates well to order inserted, but that's a side effect at best, and still requires a table scan, no? (And I don't think it answers what the OP points to as a better phrased dupe of their question: ie, without sorting)
@Diego - Why do you believe that this will be any slower than the answer you accepted?
This returns the rows upside down. You then have to re-order by them to get back the original order.
44

You can do it by using the ROW NUMBER BY PARTITION Feature also. A great example can be found here:

I am using the Orders table of the Northwind database... Now let us retrieve the Last 5 orders placed by Employee 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 

2 Comments

ROW NUMBER BY PARTITION feature uses a sort as well.. you need to sort the table to assign row numbers for each record...
This is true, but without a sort of some nature this simply won't work, the best solution is to index the major columns being hit and run with something like the above query.
19

If you want to select last numbers of rows from a table.

Syntax will be like

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

These statements work but differrent ways. thank you guys.

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

in this way you can get last 10 rows but order will show descnding way

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) 

Comments

14

In a very general way and to support SQL server here is

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

and for the performance, it is not bad (less than one second for more than 10,000 records On Server machine)

1 Comment

well 10'000 records is nothing where you should mind about performance. When you start talking about millions of records than you can start thinking about performance
10

First you most get record count from

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

And then :

In SQL Server 2012

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

In 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 

Comments

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

Comments

6

Is "Id" indexed? If not, that's an important thing to do (I suspect it is already indexed).

Also, do you need to return ALL columns? You may be able to get a substantial improvement in speed if you only actually need a smaller subset of columns which can be FULLY catered for by the index on the ID column - e.g. if you have a NONCLUSTERED index on the Id column, with no other fields included in the index, then it would have to do a lookup on the clustered index to actually get the rest of the columns to return and that could be making up a lot of the cost of the query. If it's a CLUSTERED index, or a NONCLUSTERED index that includes all the other fields you want to return in the query, then you should be fine.

Comments

4

Here's something you can try without an order by but I think it requires that each row is unique. N is the number of rows you want, L is the number of rows in the table.

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

As noted before, which rows are returned is undefined.

EDIT: this is actually dog slow. Of no value really.

Comments

4

A technique I use to query the MOST RECENT rows in very large tables (100+ million or 1+ billion rows) is limiting the query to "reading" only the most recent "N" percentage of RECENT ROWS. This is real world applications, for example I do this for non-historic Recent Weather Data, or recent News feed searches or Recent GPS location data point data.

This is a huge performance improvement if you know for certain that your rows are in the most recent TOP 5% of the table for example. Such that even if there are indexes on the Tables, it further limits the possibilites to only 5% of rows in tables which have 100+ million or 1+ billion rows. This is especially the case when Older Data will require Physical Disk reads and not only Logical In Memory reads.

This is well more efficient than SELECT TOP | PERCENT | LIMIT as it does not select the rows, but merely limit the portion of the data to be searched.

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' 

2 Comments

An interesting approach
This works well, but it needs to be in a SQL procedure. If you want a simpler query you can replace the variable usage with the select statements in (parenthesis). SQL SELECT Col1 FROM Table1 WHERE TableIdCol > (SELECT MAX(TableIdCol)-20000 from Table1) ORDER BY TableIdCol1;
4

MS doesn't support LIMIT in t-sql. Most of the times i just get MAX(ID) and then subtract.

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

This will return less than 10 records when ID is not sequential.

Comments

2

This query returns last N rows in correct order, but it's performance is poor

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

Comments

2

use desc with orderby at the end of the query to get the last values.

Comments

2

In order to get the result in ascending order

SELECT n.* FROM ( SELECT * FROM MyTable ORDER BY id DESC LIMIT N ) n ORDER BY n.id ASC 

1 Comment

For T-SQL, relace "LIMIT N" with "OFFSET 0 ROWS" followed by "FETCH NEXT N ROWS ONLY". Where N is the integer for number of rows.
1

This may not be quite the right fit to the question, but…

OFFSET clause

The OFFSET number clause enables you to skip over a number of rows and then return rows after that.

That doc link is to Postgres; I don't know if this applies to Sybase/MS SQL Server.

Comments

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 

Comments

0

Try using the EXCEPT syntax.
Something like this:

 SELECT * FROM clientDetails EXCEPT (SELECT TOP (numbers of rows - how many rows you want) * FROM clientDetails) 

1 Comment

Same answer as @Prafulla Sutradhar
0

I stumpled acros this issue while using SQL server What i did to resolve it is order the results descending and giving row number to the results of that, After i filtered the results and turned them around again.

 SELECT * FROM ( SELECT * ,[rn] = ROW_NUMBER() OVER (ORDER BY [column] DESC) FROM [table] ) A WHERE A.[rn] < 3 ORDER BY [column] ASC 

Easy copy paste answer

Comments

0

I always use a CTE to delete the very last rows like this. You can also use ROW_NUMBER() to count rows as well.

;WITH CTE AS ( SELECT *, COUNT(schoolBoundaryID) OVER(ORDER BY schoolBoundaryID DESC) AS SchoolBoundaryCount FROM [dbo].[SchoolBoundary] ) -- Deletes the last 80,42 rows. DELETE FROM CTE WHERE SchoolBoundaryCount < 8043 

Comments

0

SELECT * FROM TABLENAME WHERE COLUMNAME = SOMECONDITION ORDER BY COL1 DESC, COL2 DESC FETCH FIRST 1 ROWS ONLY;

1 Comment

Please add a description of the code, and format the code properly.
0

IF you use php and mysql combine it like so:

$find = $db->prepare("SELECT count(id) as countaggre FROM analytics_aggregate"); $find->execute(); $countaggregates = $find->fetch(PDO::FETCH_ASSOC); if($countaggregates['countaggre'] > 12) { $start = $countaggregates['countaggre'] - 12; } else { $start = 0; } $find = $db->prepare("SELECT * FROM analytics_aggregate ORDER BY id ASC LIMIT ".$start.", 12"); 

Comments

0

I use this query:

SELECT * FROM ( SELECT * FROM MyTable ORDER BY id DESC LIMIT 10 )Var1 ORDER BY id ASC; 

Comments

-1

To display last 3 rows without using 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 Comment

This will not provide predictable results. According to the Sql Server MSDN docs (msdn.microsoft.com/en-us/library/ms189463.aspx): "When TOP is used in conjunction with the ORDER BY clause, the result set is limited to the first N number of ordered rows; otherwise, it returns the first N number of rows in an undefined order."

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.