SQL Server SELECT LAST N строк

139

Это известный вопрос, но лучшее решение, которое я нашел, это что-то вроде:

SELECT TOP N *
FROM MyTable
ORDER BY Id DESC

У меня есть таблица с множеством строк. Невозможно использовать этот запрос, потому что он занимает много времени. Итак, как я могу сделать, чтобы выбрать последние N строк без использования ORDER BY?

РЕДАКТИРОВАТЬ

Извините, дублированный вопрос об этом

Диего
источник
Что подразумевается под «последним N»? Без заказа «последний N» не имеет особого смысла. Если вы имеете в виду «последний N для вставки», то вы не можете полагаться на SQL Server, чтобы дать вам это - вы должны использовать предложение ORDER BY.
Даниэль Реншоу
@Daniel Renshaw: последние N таблицы, не заставляя SQL Server упорядочивать все таблицы, потому что они работают очень медленно
Диего
Запрос в вашем вопросе - лучший способ. Если idон проиндексирован, он просто отсканирует этот индекс в обратном порядке и остановится после первых 5 строк. Если он не проиндексирован, ему нужно будет выполнить TOP Nсортировку. Это не будет хуже, чем любой другой способ сделать это. Он не сортирует всю таблицу (хотя нужно будет сканировать всю таблицу)
Martin Smith,

Ответы:

38

Вы также можете сделать это, используя функцию ROW NUMBER BY PARTITION. Отличный пример можно найти здесь :

Я использую таблицу «Заказы» базы данных «Борей» ... Теперь давайте возьмем последние 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
JonVD
источник
1
Функция ROW NUMBER BY PARTITION также использует сортировку. Вам нужно отсортировать таблицу, чтобы назначить номера строк для каждой записи ...
Садхир,
Это правда, но без какой-либо природы это просто не сработает, лучшее решение состоит в том, чтобы индексировать основные столбцы, по которым выполняется поиск, и выполнять их с помощью чего-то подобного приведенному выше запросу.
JonVD
101

Вы можете заставить сервер SQL выбирать последние N строк, используя этот SQL:

select * from tbl_name order by id desc limit N;
Ниру Мукунд Шах
источник
2
Как насчет совместимости версий?
Фракталист
63
Это не работает в SQL Server. Похоже на MySQL, PostgreSQL и SQLite.
Тим Фризен
3
Все перечисленные продукты, безусловно, являются серверами SQL. Если вы хотите поговорить о сервере MS SQL, почему бы не назвать его так?
gena2x
4
я запутался, вопрос спрашивает, как создать запрос на выборку "без использования ORDER BY", а запрос на выборку в вашем ответе имеет "order by". Это что-то вроде «заказ по» без «заказ по»?
Роберт Синклер
5
@ gena2x этот вопрос помечен SQL Server. Этот тег относится к Microsoft SQL Server.
Мартин Смит
51

Я тестировал код JonVD, но обнаружил, что он очень медленный, 6 с.

Этот код занял 0 с.

SELECT TOP(5) ORDERID, CUSTOMERID, OrderDate    
FROM Orders where EmployeeID=5    
Order By OrderDate DESC
ABI
источник
4
Сколько строк ?? Когда у вас есть много строк, которые могут быть очень медленными
Диего
@ Диего Почему это? Если вы OrderDateпроиндексированы, то по сути одинаково быстро можно выбрать первые или последние N строк запроса. Я понимаю, что есть шанс OrderDateхорошо коррелировать с введенным заказом, но это в лучшем случае побочный эффект, и все равно требуется сканирование таблицы, не так ли? (И я не думаю, что это отвечает на то, на что ОП указывает, как на лучшую формулировку своего вопроса : т.е. без сортировки)
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-сервера здесь есть

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

и для производительности это неплохо (менее одной секунды для более чем 10000 записей на сервере)

Хакан Фистик
источник
1
ну 10 000 записей - это не то, где вы должны думать о производительности. Когда вы начинаете говорить о миллионах записей, вы начинаете думать о производительности
Dom84
6

Индексируется ли "Id"? Если нет, то это важная вещь (я подозреваю, что она уже проиндексирована).

Кроме того, вам нужно вернуть все столбцы? Вы можете добиться существенного улучшения в скорости, если вам на самом деле нужно только меньшее подмножество столбцов, которые могут ПОЛНОСТЬЮ удовлетворяться с помощью индекса в столбце ID - например, если у вас есть NONCLUSTERED индекс в столбце Id, без других Поля, включенные в индекс, должны были бы выполнить поиск по кластерному индексу, чтобы фактически получить остальные столбцы для возврата, и это могло бы составить большую часть стоимости запроса. Если это индекс CLUSTERED или индекс NONCLUSTERED, который включает в себя все другие поля, которые вы хотите вернуть в запросе, то все будет в порядке.

AdaTheDev
источник
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]
Timberhill
источник
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
Slava
источник
1

MS не поддерживает LIMIT в t-sql. В большинстве случаев я просто получаю МАКС (ID) и затем вычитаю.

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

Это вернет менее 10 записей, если идентификатор не является последовательным.

olafk
источник
0

Техника, которую я использую для запроса самых последних строк в очень больших таблицах (100+ миллионов или 1+ миллиардов строк) , ограничивает запрос «чтением» только самого последнего «N» процента от RECENT ROWS. Это приложения реального мира, например, я делаю это для неисторических недавних данных о погоде или недавних поисков в новостной ленте или недавних данных о точках данных о местоположении GPS.

Это огромное улучшение производительности, если вы точно знаете, что ваши строки находятся в последних 5% ТОП таблицы, например. Таким образом, даже если в таблицах есть индексы, это дополнительно ограничивает возможности только 5% строк в таблицах, которые имеют более 100 миллионов или более 1 миллиарда строк. Это особенно актуально, когда для старых данных требуются чтения с физического диска, а не только чтения из логической памяти .

Это намного эффективнее, чем SELECT TOP | ПРОЦЕНТ | 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'
CodeCowboyOrg
источник
-1

Для отображения последних 3 строк без использования 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
Это не даст предсказуемых результатов. В соответствии с документами MSDN Sql Server ( msdn.microsoft.com/en-us/library/ms189463.aspx ): «Когда TOP используется вместе с предложением ORDER BY, результирующий набор ограничен первым N числом упорядоченных Строки; в противном случае он возвращает первое число N строк в неопределенном порядке. "
caveman_dick
-1

Попробуйте использовать EXCEPTсинтаксис.
Что-то вроде этого:

   SELECT * 
    FROM   clientDetails 
    EXCEPT 
    (SELECT TOP (numbers of rows - how many rows you want) * 
     FROM   clientDetails) 
майур годхани
источник
Тот же ответ, что и у @Prafulla Sutradhar
DMK
-1

Может быть, немного поздно, но вот простой выбор, который решит ваш вопрос.

SELECT * FROM "TABLE" T ORDER BY "T.ID_TABLE" DESC LIMIT 5;
Лукас Орсо
источник