180

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

Community
  • 1
  • 1
Diego
  • 16,026
  • 24
  • 80
  • 135
  • 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. – Daniel Renshaw Nov 16 '10 at 12:16
  • @Daniel Renshaw: The last N of the table without forcing SQL Server to order all table because it gets really slow – Diego Nov 16 '10 at 12:30
  • 1
    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`](http://sqlblog.com/blogs/paul_white/archive/2010/08/27/sorting-row-goals-and-the-top-100-problem.aspx) 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) – Martin Smith Sep 28 '12 at 07: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. – onefootswill Aug 16 '21 at 23:37

18 Answers18

145

You can get SQL server to select the last N rows with the following query:

select * from tbl_name order by id desc limit N;
Spaghetti
  • 127
  • 8
Niru Mukund Shah
  • 4,525
  • 2
  • 18
  • 34
  • 2
    How about version compatibility? – Fractaliste Jul 02 '14 at 14:06
  • 83
    This does not work in SQL Server. Seems like a MySQL, PostgreSQL, and SQLite feature. – Tim Friesen Oct 14 '14 at 20:35
  • some more explanation [here](https://ask.sqlservercentral.com/questions/2013/how-to-select-bottom-n-rows-in-a-table-through-sin.html) – Shaiju T Jun 17 '15 at 08:00
  • 3
    All enumerated products are definetly SQL servers. If you want to talk about MS SQL server, why not name it so? – gena2x Jun 08 '16 at 09:45
  • 5
    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"? – Robert Sinclair Dec 21 '16 at 19:46
  • 7
    @gena2x this question is tagged SQL Server. That tag refers to Microsoft SQL Server. – Martin Smith Sep 30 '17 at 23:29
  • 1
    to use this in SQL server use the following: select top(1) * from tbl_name order by id desc; or use: SET ROWCOUNT=1 select * from tbl_name order by id desc; SET ROWCOUNT =0 I prefer the first, the last works in all versions starting SQL 6,5 and can be used with delete and update as well. – Walter Verhoeven Mar 25 '18 at 22:44
59

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
Compass
  • 5,692
  • 4
  • 28
  • 40
ABI
  • 1,584
  • 12
  • 13
  • 4
    How many rows?? When you've got lot of rows that can be REALY slow – Diego Nov 16 '10 at 12:11
  • @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](http://stackoverflow.com/questions/311054/how-do-i-select-last-5-rows-in-a-table-without-sorting): ie, without sorting) – ruffin Apr 05 '16 at 15:07
  • 1
    @Diego - Why do you believe that this will be any slower than the answer you accepted? – Martin Smith Oct 01 '17 at 12:45
  • 3
    This returns the rows upside down. You then have to re-order by them to get back the original order. – Mark Nov 24 '17 at 09:53
41

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
ruffin
  • 15,005
  • 8
  • 80
  • 126
JonVD
  • 4,179
  • 22
  • 24
  • 1
    ROW NUMBER BY PARTITION feature uses a sort as well.. you need to sort the table to assign row numbers for each record... – Sadhir Nov 16 '10 at 15:17
  • 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. – JonVD Nov 16 '10 at 23:15
18

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)
Baby Groot
  • 4,617
  • 39
  • 52
  • 69
9

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)

Hakan Fıstık
  • 14,367
  • 10
  • 94
  • 117
  • 2
    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 – Dom84 Apr 06 '17 at 08:59
7

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 
Ardalan Shahgholi
  • 10,987
  • 15
  • 102
  • 133
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.

AdaTheDev
  • 135,750
  • 27
  • 195
  • 192
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.

Dzamo Norton
  • 954
  • 10
  • 16
4
select * from (select top 6 * from vwTable order by Hours desc) T order by Hours
Matt Cain
  • 5,468
  • 3
  • 34
  • 45
fth
  • 41
  • 1
3

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.

olafk
  • 59
  • 1
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]
timberhill
  • 67
  • 1
  • 7
2

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'
CodeCowboyOrg
  • 2,723
  • 1
  • 13
  • 11
  • An interesting approach – Majid Qafouri Nov 01 '21 at 13:49
  • 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; ``` – Rashi Abramson Jan 13 '22 at 21:25
2

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

Sara
  • 49
  • 8
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.

Basil Bourque
  • 262,936
  • 84
  • 758
  • 1,028
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
Slava
  • 3,367
  • 1
  • 19
  • 16
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

Kaede
  • 188
  • 1
  • 11
-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) 
NullUserException
  • 81,190
  • 27
  • 202
  • 228
abhinay
  • 19
  • 1
    This will not provide predictable results. According to the Sql Server MSDN docs (http://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." – caveman_dick Oct 15 '12 at 12:30
-1

Try using the EXCEPT syntax.
Something like this:

   SELECT * 
    FROM   clientDetails 
    EXCEPT 
    (SELECT TOP (numbers of rows - how many rows you want) * 
     FROM   clientDetails) 
Gidil
  • 4,079
  • 2
  • 31
  • 48